linking refactor

This commit is contained in:
GenevensiS
2026-02-01 17:39:33 +01:00
parent 7fde6b2605
commit 11e506739a
18 changed files with 411 additions and 407 deletions
+87 -78
View File
@@ -22,66 +22,74 @@ AddCardAction::AddCardAction(Set& set)
, action(ADD, make_intrusive<Card>(*set.game), set.cards)
{}
AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const CardP& card)
: CardListAction(set)
, action(ar, card, set.cards)
{}
AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>& cards)
: CardListAction(set)
, action(ar, cards, set.cards)
{}
{
// If we are adding cards, resolve any uid conflicts
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
// and never because two different cards randomly got assigned the same uid
if (!action.adding) return;
// Tally existing unique ids
unordered_map<String, CardP> all_existing_cards;
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_cards.insert({ card->uid, card });
all_existing_uids.insert(card->uid);
}
// Tally added unique ids
unordered_map<String, CardP> all_added_uids;
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
CardP card = action.steps[pos].item;
all_added_uids.insert({ card->uid, card });
}
// Cycle on the added cards
unordered_map<String, CardP> all_added_uids_copy(all_added_uids);
FOR_EACH(added_pair, all_added_uids_copy) {
String old_uid = added_pair.first;
CardP added_card = added_pair.second;
// Assign new unique id if necessary
if (all_existing_cards.find(old_uid) == all_existing_cards.end()) continue;
String new_uid = generate_uid();
added_card->uid = new_uid;
all_added_uids.insert({ new_uid, added_card });
// Update links on linked cards
LINK_PAIRS(linked_pairs, added_card);
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
String& linked_relation = linked_pair.second.get();
if (linked_uid.empty()) continue;
// If it's an added card, replace the link
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
all_added_uids.at(linked_uid)->updateLinkedUID(old_uid, new_uid);
}
// Otherwise, if it's an existing card, create an action to copy the link
else if (all_existing_cards.find(linked_uid) != all_existing_cards.end()) {
CardP linked_card = all_existing_cards.at(linked_uid);
int linked_index = linked_card->findFreeLink(new_uid, all_existing_uids);
if (linked_index < 0) {
queue_message(MESSAGE_WARNING, _ERROR_1_("not enough free links", linked_card->identification()));
}
else {
String relation(linked_card->getLinkedRelation(linked_index));
card_link_actions.push_back(make_intrusive<OneWayLinkCardsAction>(set, linked_card, new_uid, relation, linked_index));
}
}
}
}
}
String AddCardAction::getName(bool to_undo) const {
return action.getName();
}
void AddCardAction::perform(bool to_undo) {
// If we are adding cards, resolve any uid conflicts
// (If we are re-adding cards, from a remove undo, there shouldn't be any uid conflicts)
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
// and never because two different cards randomly got assigned the same uid
if (action.adding && !to_undo) {
// Tally existing unique ids
unordered_map<String, CardP> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_uids.insert({ card->uid, card });
}
// Tally added unique ids
unordered_map<String, CardP> all_added_uids;
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
CardP card = action.steps[pos].item;
all_added_uids.insert({ card->uid, card });
}
FOR_EACH(added_pair, all_added_uids) {
String old_uid = added_pair.first;
CardP added_card = added_pair.second;
// Assign new unique ids
if (all_existing_uids.find(old_uid) != all_existing_uids.end()) {
String new_uid = generate_uid();
added_card->uid = new_uid;
all_added_uids.insert({ new_uid, added_card });
// Update links on linked cards
OTHER_LINKED_PAIRS(linked_pairs, added_card);
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
String& linked_relation = linked_pair.second.get();
if (linked_uid.empty()) continue;
// If it's an added card, replace the link
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
all_added_uids.at(linked_uid)->updateLink(old_uid, new_uid);
}
// Otherwise, if it's an existing card, copy the link
else if (all_existing_uids.find(linked_uid) != all_existing_uids.end()) {
all_existing_uids.at(linked_uid)->copyLink(set, old_uid, new_uid);
}
}
}
}
}
// Add or remove cards
action.perform(set.cards, to_undo);
// Update card links
for (int i = 0; i < card_link_actions.size(); ++i) {
card_link_actions[i]->perform(to_undo);
}
}
// ----------------------------------------------------------------------------- : Reorder cards
@@ -108,39 +116,40 @@ void ReorderCardsAction::perform(bool to_undo) {
// ----------------------------------------------------------------------------- : Link cards
LinkCardsAction::LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
: CardListAction(set), selected_card(selected_card), linked_cards(linked_cards), selected_relation(selected_relation), linked_relation(linked_relation)
{}
String LinkCardsAction::getName(bool to_undo) const {
return _("Link cards");
}
void LinkCardsAction::perform(bool to_undo) {
if (!to_undo) {
selected_card->link(set, linked_cards, selected_relation, linked_relation);
} else {
selected_card->unlink(linked_cards);
OneWayLinkCardsAction::OneWayLinkCardsAction(Set& set, CardP& card, const String& uid, const String& relation, int index)
: CardListAction(set), card(card), uid(uid), relation(relation)
{
switch (index) {
case 1: {
linked_uid = &card->linked_card_1;
linked_relation = &card->linked_relation_1;
return;
}
case 2: {
linked_uid = &card->linked_card_2;
linked_relation = &card->linked_relation_2;
return;
}
case 3: {
linked_uid = &card->linked_card_3;
linked_relation = &card->linked_relation_3;
return;
}
default: {
linked_uid = &card->linked_card_4;
linked_relation = &card->linked_relation_4;
return;
}
}
}
UnlinkCardsAction::UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card)
: CardListAction(set), selected_card(selected_card), unlinked_card(unlinked_card)
{}
String UnlinkCardsAction::getName(bool to_undo) const {
return _("Unlink card");
String OneWayLinkCardsAction::getName(bool to_undo) const {
return _("Change link");
}
void UnlinkCardsAction::perform(bool to_undo) {
if (!to_undo) {
pair<String, String> relations = selected_card->unlink(unlinked_card);
selected_relation = relations.first;
unlinked_relation = relations.second;
}
else {
selected_card->link(set, unlinked_card, selected_relation, unlinked_relation);
}
void OneWayLinkCardsAction::perform(bool to_undo) {
swap(*linked_uid, uid);
swap(*linked_relation, relation);
}
// ----------------------------------------------------------------------------- : Change stylesheet
@@ -236,7 +245,7 @@ String ChangeCardUIDAction::getName(bool to_undo) const {
}
void ChangeCardUIDAction::perform(bool to_undo) {
FOR_EACH(c, set.cards) {
c->updateLink(card->uid, uid);
c->updateLinkedUID(card->uid, uid);
}
swap(card->uid, uid);
}
+8 -21
View File
@@ -41,13 +41,13 @@ class AddCardAction : public CardListAction {
public:
/// Add a newly allocated card
AddCardAction(Set& set);
AddCardAction(AddingOrRemoving, Set& set, const CardP& card);
AddCardAction(AddingOrRemoving, Set& set, const vector<CardP>& cards);
String getName(bool to_undo) const override;
void perform(bool to_undo) override;
const GenericAddAction<CardP> action;
vector<ActionP> card_link_actions;
};
// ----------------------------------------------------------------------------- : Reorder cards
@@ -67,32 +67,19 @@ public:
// ----------------------------------------------------------------------------- : Link cards
/// Add a link between two or more cards
class LinkCardsAction : public CardListAction {
class OneWayLinkCardsAction : public CardListAction {
public:
LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation);
OneWayLinkCardsAction(Set& set, CardP& card, const String& uid, const String& relation, int index);
String getName(bool to_undo) const override;
void perform(bool to_undo) override;
//private:
CardP selected_card; ///< The card currently selected in the cards tab
vector<CardP> linked_cards; ///< The cards that will be linked to the selected card
String selected_relation; ///< The nature of the relation of the selected card
String linked_relation; ///< The nature of the relation of the linked cards
};
/// Remove a link between two cards
class UnlinkCardsAction : public CardListAction {
public:
UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card);
String getName(bool to_undo) const override;
void perform(bool to_undo) override;
//private:
CardP selected_card; ///< The card currently selected in the cards tab
CardP unlinked_card; ///< The card that will be unlinked from the selected card
String selected_relation; ///< The nature of the relation of the selected card
String unlinked_relation; ///< The nature of the relation of the unlinked card
CardP card; ///< The card we change the link of. We hold a reference so it doesn't get destroyed before this.
String* linked_uid; ///< The uid slot we need to change
String* linked_relation; ///< The relation slot we need to change
String uid; ///< The uid we have to change the link to
String relation; ///< The relation we have to change the link to
};
// ----------------------------------------------------------------------------- : Change stylesheet
+3 -3
View File
@@ -212,12 +212,12 @@ void ScriptStyleEvent::perform(bool) {
// ----------------------------------------------------------------------------- : Bulk action
BulkAction::BulkAction(const vector<shared_ptr<Action>>& actions, const SetP& set, CardListBase* card_list_window)
BulkAction::BulkAction(const vector<ActionP>& actions, const SetP& set, CardListBase* card_list_window)
: actions(actions), set(set), card_list_window(card_list_window)
{
if (actions.empty()) throw ScriptError(_("BulkAction created with no actions"));
name_do = actions.front()->getName(false) + _(" ") + _ACTION_("bulk");
name_undo = actions.front()->getName(true) + _(" ") + _ACTION_("bulk");
name_do = _ACTION_1_("bulk", actions.front()->getName(false));
name_undo = _ACTION_1_("bulk", actions.front()->getName(true));
}
BulkAction::~BulkAction() {}
+2 -2
View File
@@ -206,7 +206,7 @@ public:
// An action that's just a list of other actions
class BulkAction : public Action {
public:
BulkAction(const vector<shared_ptr<Action>>& actions, const SetP& set, CardListBase* card_list_window);
BulkAction(const vector<ActionP>& actions, const SetP& set, CardListBase* card_list_window);
~BulkAction() override;
String getName(bool to_undo) const override;
@@ -216,7 +216,7 @@ public:
private:
String name_do;
String name_undo;
vector<shared_ptr<Action>> actions;
vector<ActionP> actions;
SetP set;
CardListBase* card_list_window;
};
+132 -209
View File
@@ -65,203 +65,108 @@ bool Card::contains(QuickFilterPart const& query) const {
return false;
}
void Card::link(const Set& set, const vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
{
unlink(linked_cards);
vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_set<String>& all_existing_uids) {
vector<int> freeIndexes;
int count = min(4, (int)linked_uids.size());
LINK_PAIRS(linked_pairs, this);
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_uids.insert(card->uid);
}
int free_link_count = 0;
THIS_LINKED_PAIRS(this_linked_pairs);
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
if (
this_linked_uid.empty() || // Not a reference
all_existing_uids.find(this_linked_uid) == all_existing_uids.end() // Reference to nonexistent card
) free_link_count++;
}
if (free_link_count < linked_cards.size()) {
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links"));
return;
for (int i = 0; i < count; ++i) {
String& linked_uid = linked_uids[i];
// Try to find an existing link
for (int j = 0; j < linked_pairs.size(); ++j) {
auto& linked_pair = linked_pairs[j];
if (linked_pair.first.get() == linked_uid &&
std::find(freeIndexes.begin(), freeIndexes.end(), j) != freeIndexes.end()
) {
freeIndexes.push_back(j);
goto continue_outer;
}
}
// Try to find a free spot
for (int j = 0; j < linked_pairs.size(); ++j) {
auto& linked_pair = linked_pairs[j];
if (linked_pair.first.get().empty() &&
std::find(freeIndexes.begin(), freeIndexes.end(), j) != freeIndexes.end()
) {
freeIndexes.push_back(j);
goto continue_outer;
}
}
// Try to find an erasable spot
for (int j = 0; j < linked_pairs.size(); ++j) {
auto& linked_pair = linked_pairs[j];
if (all_existing_uids.find(linked_pair.first.get()) == all_existing_uids.end() &&
std::find(freeIndexes.begin(), freeIndexes.end(), j) != freeIndexes.end()
) {
freeIndexes.push_back(j);
goto continue_outer;
}
}
freeIndexes.push_back(-1);
continue_outer:;
}
return freeIndexes;
}
int Card::findFreeLink(const String& linked_uid, const unordered_set<String>& all_existing_uids) {
vector<String> linked_uids { linked_uid };
return findFreeLinks(linked_uids, all_existing_uids)[0];
}
vector<CardP> all_missed_cards;
FOR_EACH(linked_card, linked_cards) {
bool written = false;
// Try to write to a free spot
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (this_linked_uid.empty()) {
this_linked_uid = linked_card->uid;
this_linked_relation = linked_relation;
written = true;
break;
}
}
// Try to write to an erasable spot
if (!written) {
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (all_existing_uids.find(this_linked_uid) == all_existing_uids.end()) {
this_linked_uid = linked_card->uid;
this_linked_relation = linked_relation;
written = true;
break;
}
}
}
if (!written) {
// Should be impossible to end up here?
}
int Card::findUIDLink(const String& linked_uid) {
if (linked_card_1 == linked_uid) return 0;
if (linked_card_2 == linked_uid) return 1;
if (linked_card_3 == linked_uid) return 2;
if (linked_card_4 == linked_uid) return 3;
return -1;
}
OTHER_LINKED_PAIRS(linked_pairs, linked_card);
written = false;
// Try to write to a free spot
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
String& linked_relation = linked_pair.second.get();
if (linked_uid.empty()) {
linked_uid = uid;
linked_relation = selected_relation;
written = true;
break;
}
}
// Try to write to an erasable spot
if (!written) {
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
String& linked_relation = linked_pair.second.get();
if (all_existing_uids.find(linked_uid) == all_existing_uids.end()) {
linked_uid = uid;
linked_relation = selected_relation;
written = true;
break;
}
}
}
// Notify we couldn't write
if (!written) {
all_missed_cards.push_back(linked_card);
}
vector<int> Card::findRelationLinks(const String& linked_relation) {
vector<int> indexes;
if (linked_relation_1 == linked_relation) indexes.push_back(0);
if (linked_relation_2 == linked_relation) indexes.push_back(1);
if (linked_relation_3 == linked_relation) indexes.push_back(2);
if (linked_relation_4 == linked_relation) indexes.push_back(3);
return indexes;
}
String& Card::getLinkedUID(int index) {
switch (index) {
case 3: return linked_card_4;
case 2: return linked_card_3;
case 1: return linked_card_2;
default: return linked_card_1;
}
if (all_missed_cards.size() > 0) {
std::stringstream ss;
ss << _ERROR_("could not link");
for (size_t pos = 0; pos < all_missed_cards.size(); ++pos) {
ss << all_missed_cards[pos]->identification();
if (pos < all_missed_cards.size() - 1) ss << ", ";
};
queue_message(MESSAGE_WARNING, wxString(ss.str().c_str()));
}
String& Card::getLinkedRelation(int index) {
switch (index) {
case 3: return linked_relation_4;
case 2: return linked_relation_3;
case 1: return linked_relation_2;
default: return linked_relation_1;
}
}
void Card::link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation)
{
vector<CardP> linked_cards { linked_card };
link(set, linked_cards, selected_relation, linked_relation);
void Card::updateLinkedUID(const String& old_uid, const String& new_uid) {
int index = findUIDLink(old_uid);
if (index >= 0) getLinkedUID(index) = new_uid;
}
void Card::unlink(const vector<CardP>& unlinked_cards)
{
for (size_t pos = 0; pos < unlinked_cards.size(); ++pos) {
CardP unlinked_card = unlinked_cards[pos];
unlink(unlinked_card);
vector<CardP> Card::getLinkedRelationCards(const vector<CardP>& cards, const String& linked_relation, bool erase_if_no_card) {
vector<CardP> other_cards;
vector<int> indexes = findRelationLinks(linked_relation);
for (int i = 0; i < indexes.size(); ++i) {
String& linked_uid = getLinkedUID(indexes[i]);
CardP other_card = getUIDCard(cards, linked_uid);
if (other_card) other_cards.push_back(other_card);
else if (erase_if_no_card) {
linked_uid = _("");
getLinkedRelation(indexes[i]) = _("");
}
}
return other_cards;
}
pair<String, String> Card::unlink(CardP& unlinked_card)
{
String old_selected_relation = _("");
THIS_LINKED_PAIRS(this_linked_pairs);
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (this_linked_uid == unlinked_card->uid) {
old_selected_relation = this_linked_relation;
this_linked_uid = _("");
this_linked_relation = _("");
}
}
String old_unlinked_relation = _("");
OTHER_LINKED_PAIRS(unlinked_pairs, unlinked_card);
FOR_EACH(unlinked_pair, unlinked_pairs) {
String& unlinked_uid = unlinked_pair.first.get();
String& unlinked_relation = unlinked_pair.second.get();
if (unlinked_uid == uid) {
old_unlinked_relation = unlinked_relation;
unlinked_uid = _("");
unlinked_relation = _("");
}
}
return make_pair(old_selected_relation, old_unlinked_relation);
}
void Card::copyLink(const Set& set, String old_uid, String new_uid) {
// Find what relation we need to copy
String relation_copy = _("");
THIS_LINKED_PAIRS(this_linked_pairs);
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (this_linked_uid == old_uid) {
relation_copy = this_linked_relation;
break;
}
}
// Nothing to copy
if (relation_copy.empty()) {
return;
}
// Try to copy to a free spot
bool written = false;
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (this_linked_uid.empty()) {
this_linked_uid = new_uid;
this_linked_relation = relation_copy;
written = true;
break;
}
}
// Try to copy to an erasable spot
if (!written) {
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_uids.insert(card->uid);
}
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (all_existing_uids.find(this_linked_uid) == all_existing_uids.end()) {
this_linked_uid = new_uid;
this_linked_relation = relation_copy;
written = true;
break;
}
}
}
// Notify we couldn't copy
if (!written) {
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links for copy"));
}
}
void Card::updateLink(String old_uid, String new_uid) {
THIS_LINKED_PAIRS(this_linked_pairs);
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
if (this_linked_uid == old_uid) {
this_linked_uid = new_uid;
return;
}
}
vector<CardP> Card::getLinkedRelationCards(const Set& set, const String& linked_relation, bool erase_if_no_card) {
return getLinkedRelationCards(set.cards, linked_relation, erase_if_no_card);
}
vector<pair<CardP, String>> Card::getLinkedCards(const vector<CardP>& cards) {
@@ -283,7 +188,7 @@ vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
return getLinkedCards(set.cards);
}
CardP Card::getLinkedOtherFace(const vector<CardP>& cards) {
CardP Card::getLinkedOtherFaceCard(const vector<CardP>& cards) {
unordered_set<String> faces;
if (linked_relation_1 == _("Front Face") || linked_relation_1 == _("Back Face")) faces.emplace(linked_card_1);
if (linked_relation_2 == _("Front Face") || linked_relation_2 == _("Back Face")) faces.emplace(linked_card_2);
@@ -294,39 +199,57 @@ CardP Card::getLinkedOtherFace(const vector<CardP>& cards) {
}
return nullptr;
}
CardP Card::getLinkedOtherFace(const Set& set) {
return getLinkedOtherFace(set.cards);
CardP Card::getLinkedOtherFaceCard(const Set& set) {
return getLinkedOtherFaceCard(set.cards);
}
vector<CardP> Card::getLinkedCardsFromLink(const vector<CardP>& cards, const String& link, bool erase_if_no_card) {
vector<CardP> other_cards;
THIS_LINKED_PAIRS(this_linked_pairs);
FOR_EACH(this_linked_pair, this_linked_pairs) {
String& this_linked_uid = this_linked_pair.first.get();
String& this_linked_relation = this_linked_pair.second.get();
if (this_linked_relation == link) {
CardP other_card = getCardFromUid(cards, this_linked_uid);
if (other_card) other_cards.push_back(other_card);
else if (erase_if_no_card) {
this_linked_relation = _("");
this_linked_uid = _("");
}
}
void Card::addLink(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation) {
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_uids.insert(card->uid);
}
int index = findFreeLink(linked_card->uid, all_existing_uids);
if (index < 0) {
queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", identification()));
return;
}
getLinkedUID(index) = linked_card->uid;
getLinkedRelation(index) = selected_relation;
index = linked_card->findFreeLink(uid, all_existing_uids);
if (index < 0) {
queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", linked_card->identification()));
}
else {
linked_card->getLinkedUID(index) = uid;
linked_card->getLinkedRelation(index) = linked_relation;
}
return other_cards;
}
vector<CardP> Card::getLinkedCardsFromLink(const Set& set, const String& link, bool erase_if_no_card) {
return getLinkedCardsFromLink(set.cards, link, erase_if_no_card);
}
CardP Card::getCardFromUid(const vector<CardP>& cards, const String& uid) {
void Card::removeLink(const CardP& linked_card)
{
int index = findUIDLink(linked_card->uid);
if (index >= 0) {
getLinkedUID(index) = _("");
getLinkedRelation(index) = _("");
}
index = linked_card->findUIDLink(uid);
if (index >= 0) {
linked_card->getLinkedUID(index) = _("");
linked_card->getLinkedRelation(index) = _("");
}
}
CardP Card::getUIDCard(const vector<CardP>& cards, const String& uid) {
FOR_EACH(card, cards) {
if (card->uid == uid) return card;
}
return nullptr;
}
CardP Card::getCardFromUid(const Set& set, const String& uid) {
return getCardFromUid(set.cards, uid);
CardP Card::getUIDCard(const Set& set, const String& uid) {
return getUIDCard(set.cards, uid);
}
IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) {
+42 -23
View File
@@ -13,6 +13,7 @@
#include <util/error.hpp>
#include <data/filter.hpp>
#include <data/field.hpp> // for Card::value
#include <unordered_set>
class Game;
class Dependency;
@@ -23,8 +24,7 @@ DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(StyleSheet);
#define THIS_LINKED_PAIRS(var) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(linked_card_1), ref(linked_relation_1)), make_pair(ref(linked_card_2), ref(linked_relation_2)), make_pair(ref(linked_card_3), ref(linked_relation_3)), make_pair(ref(linked_card_4), ref(linked_relation_4)) }
#define OTHER_LINKED_PAIRS(var, other_card) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(other_card->linked_card_1), ref(other_card->linked_relation_1)), make_pair(ref(other_card->linked_card_2), ref(other_card->linked_relation_2)), make_pair(ref(other_card->linked_card_3), ref(other_card->linked_relation_3)), make_pair(ref(other_card->linked_card_4), ref(other_card->linked_relation_4)) }
#define LINK_PAIRS(var, card) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(card->linked_card_1), ref(card->linked_relation_1)), make_pair(ref(card->linked_card_2), ref(card->linked_relation_2)), make_pair(ref(card->linked_card_3), ref(card->linked_relation_3)), make_pair(ref(card->linked_card_4), ref(card->linked_relation_4)) }
// ----------------------------------------------------------------------------- : Card
@@ -80,27 +80,6 @@ public:
/// Does any field contains the given query string?
bool contains(QuickFilterPart const& query) const;
/// Link or unlink other cards to this card
void link(const Set& set, const vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation);
void link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation);
void unlink(const vector<CardP>& linked_cards);
pair<String, String> unlink(CardP& unlinked_card); // Returns the relations that were deleted, so we can undo
void copyLink(const Set& set, String old_uid, String new_uid);
void updateLink(String old_uid, String new_uid);
vector<pair<CardP, String>> getLinkedCards(const vector<CardP>& cards);
vector<pair<CardP, String>> getLinkedCards(const Set& set);
vector<CardP> getLinkedCardsFromLink(const vector<CardP>& cards, const String& link, bool erase_if_no_card);
vector<CardP> getLinkedCardsFromLink(const Set& set, const String& link, bool erase_if_no_card);
CardP getLinkedOtherFace(const vector<CardP>& cards);
CardP getLinkedOtherFace(const Set& set);
static CardP getCardFromUid(const vector<CardP>& cards, const String& uid);
static CardP getCardFromUid(const Set& set, const String& uid);
/// Find a value in the data by name and type
template <typename T> T& value(const String& name) {
for(IndexMap<FieldP, ValueP>::iterator it = data.begin() ; it != data.end() ; ++it) {
@@ -123,6 +102,46 @@ public:
throw InternalError(_("Expected a card field with name '")+name+_("'"));
}
/// Find the index of a free link slot to write to. Returns -1 if not found.
int findFreeLink (const String& linked_uid, const unordered_set<String>& all_existing_uids);
vector<int> findFreeLinks(vector<String>& linked_uids, const unordered_set<String>& all_existing_uids);
/// Find the index of a link slot that references the linked_uid. Returns -1 if not found.
int findUIDLink(const String& linked_uid);
/// Find all indexes of link slots that references the linked_relation.
vector<int> findRelationLinks(const String& linked_relation);
/// Get a reference to the linked uid slot.
String& getLinkedUID (int index);
/// Get a reference to the linked relation slot.
String& getLinkedRelation(int index);
/// Make all links that point to old_uid point to new_uid instead.
void updateLinkedUID(const String& old_uid, const String& new_uid);
/// Make all links that have old_relation have new_relation instead. Not needed apparently.
//void updateLinkedRelation(const String& old_relation, const String& new_relation);
/// Get the card with the given uid.
static CardP getUIDCard(const vector<CardP>& cards, const String& uid);
static CardP getUIDCard(const Set& set, const String& uid);
/// Get all the cards linked to this card with the given relation.
vector<CardP> getLinkedRelationCards(const vector<CardP>& cards, const String& linked_relation, bool erase_if_no_card = true);
vector<CardP> getLinkedRelationCards(const Set& set, const String& linked_relation, bool erase_if_no_card = true);
/// Get all the cards linked to this card.
vector<pair<CardP, String>> getLinkedCards(const vector<CardP>& cards);
vector<pair<CardP, String>> getLinkedCards(const Set& set);
/// Get the back face or front face of this card.
CardP getLinkedOtherFaceCard(const vector<CardP>& cards);
CardP getLinkedOtherFaceCard(const Set& set);
/// Link a card to this card.
void addLink(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation);
/// Unlink a card from this card.
void removeLink(const CardP& linked_card);
DECLARE_REFLECTION();
};
+18 -16
View File
@@ -67,6 +67,19 @@ IMPLEMENT_REFLECTION(Game) {
REFLECT_NO_SCRIPT(auto_replaces);
}
void Game::add_alt_name_or_warn(const String& alt_name, const String& field_name)
{
String unified_name = unified_form(alt_name);
if (card_fields_alt_names.count(unified_name)) {
if (card_fields_alt_names[unified_name] != field_name) {
queue_message(MESSAGE_WARNING, _("Duplicate alt card field name ' ") + unified_name + _(" ' is both an alt for: ' ") + field_name + _(" ' and ' ") + card_fields_alt_names[unified_name] + _(" '."));
}
}
else {
card_fields_alt_names.emplace(unified_name, field_name);
}
}
void Game::validate(Version v) {
// check that we have at least one card field
if (card_fields.size() < 1) {
@@ -105,23 +118,12 @@ void Game::validate(Version v) {
// alternate card field names map
for (auto it = card_fields.begin(); it != card_fields.end(); ++it) {
FieldP field = *it;
String unified_name = unified_form(field->name);
if (card_fields_alt_names.count(unified_name)) {
queue_message(MESSAGE_WARNING, _("Duplicate alternate card field name: ") + unified_name);
}
else {
card_fields_alt_names.emplace(unified_name, field->name);
}
//String column_name = field->card_list_name.get();
//card_fields_alt_names.emplace(unified_form(column_name), field->name);
String& field_name = field->name;
add_alt_name_or_warn(field_name, field_name);
add_alt_name_or_warn(field->card_list_name.default_, field_name);
add_alt_name_or_warn(field->card_list_name.get(), field_name);
for (auto it2 = field->alt_names.begin(); it2 != field->alt_names.end(); ++it2) {
unified_name = unified_form(*it2);
if (card_fields_alt_names.count(unified_name)) {
queue_message(MESSAGE_WARNING, _("Duplicate alternate card field name: ") + unified_name);
}
else {
card_fields_alt_names.emplace(unified_name, field->name);
}
add_alt_name_or_warn(*it2, field_name);
}
}
// front face/back face card link
+1
View File
@@ -78,6 +78,7 @@ public:
bool isMagic() const;
protected:
void add_alt_name_or_warn(const String& alt_name, const String& field_name);
void validate(Version) override;
DECLARE_REFLECTION_OVERRIDE();
+11 -11
View File
@@ -204,7 +204,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
return;
}
// get the new script values
vector<shared_ptr<Action>> actions;
vector<ActionP> actions;
String field_name = field_type->GetString(field_type->GetSelection());
// stylesheet, notes or id change
if (field_name == _("stylesheet") || field_name == _("notes") || field_name == _("id")) {
@@ -226,15 +226,15 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
if (field_name == _("stylesheet")) {
for (int i = 0; i < count; ++i) {
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, new_values[i]);
actions.push_back(make_shared<ChangeCardStyleAction>(cards[i], stylesheet));
actions.push_back(make_intrusive<ChangeCardStyleAction>(cards[i], stylesheet));
}
} else if (field_name == _("notes")) {
for (int i = 0; i < count; ++i) {
actions.push_back(make_shared<ChangeCardNotesAction>(cards[i], new_values[i]));
actions.push_back(make_intrusive<ChangeCardNotesAction>(cards[i], new_values[i]));
}
} else if (field_name == _("id")) {
for (int i = 0; i < count; ++i) {
actions.push_back(make_shared<ChangeCardUIDAction>(*set, cards[i], new_values[i]));
actions.push_back(make_intrusive<ChangeCardUIDAction>(*set, cards[i], new_values[i]));
}
}
}
@@ -265,7 +265,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
}
TextValue* value = dynamic_cast<TextValue*>(values[i]);
TextValue::ValueType new_value = new_values[i]->toString();
shared_ptr<SimpleValueAction<TextValue, false>> action = make_shared<SimpleValueAction<TextValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<TextValue, false>> action = make_intrusive<SimpleValueAction<TextValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
@@ -280,7 +280,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
}
MultipleChoiceValue* value = dynamic_cast<MultipleChoiceValue*>(values[i]);
MultipleChoiceValue::ValueType new_value = { new_values[i]->toString(), _("") };
shared_ptr<SimpleValueAction<MultipleChoiceValue, false>> action = make_shared<SimpleValueAction<MultipleChoiceValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<MultipleChoiceValue, false>> action = make_intrusive<SimpleValueAction<MultipleChoiceValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
@@ -295,7 +295,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
}
ChoiceValue* value = dynamic_cast<ChoiceValue*>(values[i]);
ChoiceValue::ValueType new_value = new_values[i]->toString();
shared_ptr<SimpleValueAction<ChoiceValue, false>> action = make_shared<SimpleValueAction<ChoiceValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<ChoiceValue, false>> action = make_intrusive<SimpleValueAction<ChoiceValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
@@ -310,7 +310,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
}
PackageChoiceValue* value = dynamic_cast<PackageChoiceValue*>(values[i]);
PackageChoiceValue::ValueType new_value = new_values[i]->toString();
shared_ptr<SimpleValueAction<PackageChoiceValue, false>> action = make_shared<SimpleValueAction<PackageChoiceValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<PackageChoiceValue, false>> action = make_intrusive<SimpleValueAction<PackageChoiceValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
@@ -321,7 +321,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
try {
ColorValue::ValueType new_value = new_values[i]->toColor();
ColorValue* value = dynamic_cast<ColorValue*>(values[i]);
shared_ptr<SimpleValueAction<ColorValue, false>> action = make_shared<SimpleValueAction<ColorValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<ColorValue, false>> action = make_intrusive<SimpleValueAction<ColorValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
@@ -338,7 +338,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
if (ExternalImage* img = dynamic_cast<ExternalImage*>(new_values[i].get())) {
ImageValue* value = dynamic_cast<ImageValue*>(values[i]);
ImageValue::ValueType new_value = LocalFileName::fromReadString(img->toString(), "");
shared_ptr<SimpleValueAction<ImageValue, false>> action = make_shared<SimpleValueAction<ImageValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<ImageValue, false>> action = make_intrusive<SimpleValueAction<ImageValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
@@ -355,7 +355,7 @@ void BulkModificationWindow::onOk(wxCommandEvent&) {
if (ExternalImage* img = dynamic_cast<ExternalImage*>(new_values[i].get())) {
SymbolValue* value = dynamic_cast<SymbolValue*>(values[i]);
SymbolValue::ValueType new_value = LocalFileName::fromReadString(img->toString(), "");
shared_ptr<SimpleValueAction<SymbolValue, false>> action = make_shared<SimpleValueAction<SymbolValue, false>>(value, new_value);
intrusive_ptr<SimpleValueAction<SymbolValue, false>> action = make_intrusive<SimpleValueAction<SymbolValue, false>>(value, new_value);
action->setCard(cards[i]);
actions.push_back(action);
}
+1 -1
View File
@@ -27,10 +27,10 @@ protected:
wxStaticText* modification_description, *modification_errors, *predicate_description, *predicate_errors;
wxTextCtrl* modification, *predicate;
bool modification_parsed, predicate_parsed;
ScriptP modification_script, predicate_script;
wxButton* ok_button;
SetP set;
Window* parent;
ScriptP modification_script, predicate_script;
void onSelectionChange(wxCommandEvent&);
void changeSelection();
+61 -5
View File
@@ -9,17 +9,19 @@
#include <util/prec.hpp>
#include <data/game.hpp>
#include <data/card_link.hpp>
#include <data/action/value.hpp>
#include <gui/card_link_window.hpp>
#include <gui/control/select_card_list.hpp>
#include <util/window_id.hpp>
#include <data/action/set.hpp>
#include <wx/statline.h>
#include <unordered_set>
// ----------------------------------------------------------------------------- : ExportCardSelectionChoice
CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& selected_card, bool sizer)
: wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, set(set), selected_card(selected_card)
: wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxPoint(400,-1), wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, set(set), parent(parent), selected_card(selected_card)
{
// init controls
selected_relation = new wxTextCtrl(this, wxID_ANY, _(""));
@@ -39,7 +41,7 @@ CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& sel
// init sizers
if (sizer) {
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(new wxStaticText(this, -1, _LABEL_("linked cards relation")), 0, wxALL, 8);
s->Add(new wxStaticText(this, -1, _LABEL_1_("linked cards relation", selected_card->identification())), 0, wxALL, 8);
s->Add(relation_type, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("selected card")), 0, wxALL, 4);
s->Add(selected_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
@@ -95,19 +97,73 @@ void CardLinkWindow::onRelationTypeChange(wxCommandEvent&) {
}
void CardLinkWindow::onOk(wxCommandEvent&) {
wxBusyCursor wait;
// get the context
CardListBase* card_list_window = dynamic_cast<CardListBase*>(parent);
if (!card_list_window) {
queue_message(MESSAGE_ERROR, _("Bulk modification must be called from a card list window!"));
EndModal(wxID_ABORT);
return;
}
// Perform the linking
// The selected_card is the one selected on the main cards tab
// The linked_cards are the ones selected in this dialogue window
vector<CardP> linked_cards;
getSelection(linked_cards);
// Check that we are not linking to self
if (std::find(linked_cards.begin(), linked_cards.end(), selected_card) != linked_cards.end()) {
queue_message(MESSAGE_WARNING, _ERROR_("cant link to self"));
linked_cards.erase(std::remove(linked_cards.begin(), linked_cards.end(), selected_card), linked_cards.end());
}
vector<String> linked_uids;
for (int i = 0; i < linked_cards.size(); ++i) {
linked_uids.push_back(linked_cards[i]->uid);
}
// Find free links
unordered_set<String> all_existing_uids;
FOR_EACH(card, set->cards) {
all_existing_uids.insert(card->uid);
}
vector<int> free_link_indexes = selected_card->findFreeLinks(linked_uids, all_existing_uids);
int free_link_count = 0;
for (int i = 0; i < free_link_indexes.size(); ++i) {
if (free_link_indexes[i] >= 0) free_link_count++;
}
if (free_link_count < linked_cards.size()) {
wxMessageDialog dial = wxMessageDialog(this, _ERROR_1_("missing free links", wxString::Format(wxT("%i"), free_link_count)));
dial.ShowModal();
return;
}
// Get the relations
String selected_relation_string;
String linked_relation_string;
int index = relation_type->GetSelection();
if (index >= set->game->card_links.size()) { // Custom type
set->actions.addAction(make_unique<LinkCardsAction>(*set, selected_card, linked_cards, selected_relation->GetValue(), linked_relation->GetValue()));
selected_relation_string = selected_relation->GetValue();
linked_relation_string = linked_relation->GetValue();
}
else {
CardLinkP link = set->game->card_links[index];
set->actions.addAction(make_unique<LinkCardsAction>(*set, selected_card, linked_cards, link->selected.default_, link->linked.default_));
selected_relation_string = link->selected.default_;
linked_relation_string = link->linked.default_;
}
// Make the actions
vector<ActionP> actions;
for (int i = 0; i < free_link_indexes.size(); ++i) {
if (free_link_indexes[i] >= 0) {
actions.push_back(make_intrusive<OneWayLinkCardsAction>(*set, selected_card, linked_uids[i], selected_relation_string, free_link_indexes[i]));
}
}
// Find reciprocal free slots and make actions
String& selected_uid = selected_card->uid;
for (int i = 0; i < linked_cards.size(); ++i) {
int free_link_index = linked_cards[i]->findFreeLink(selected_uid, all_existing_uids);
if (free_link_index >= 0) {
actions.push_back(make_intrusive<OneWayLinkCardsAction>(*set, linked_cards[i], selected_uid, linked_relation_string, free_link_index));
}
}
// Add action to set
set->actions.addAction(make_unique<BulkAction>(actions, set, card_list_window), false);
// Done
EndModal(wxID_OK);
}
+1
View File
@@ -43,6 +43,7 @@ protected:
SetP set;
CardP selected_card;
wxButton* sel_none;
Window* parent;
void onRelationTypeChange(wxCommandEvent&);
+6 -2
View File
@@ -450,8 +450,12 @@ bool CardListBase::doLink() {
}
return false;
}
bool CardListBase::doUnlink(CardP unlinked_card) {
set->actions.addAction(make_unique<UnlinkCardsAction>(*set, getCard(), unlinked_card));
bool CardListBase::doUnlink(CardP linked_card) {
CardP selected_card = getCard();
vector<ActionP> actions;
actions.emplace_back(make_intrusive<OneWayLinkCardsAction>(*set, selected_card, _(""), _(""), selected_card->findUIDLink(linked_card->uid)));
actions.emplace_back(make_intrusive<OneWayLinkCardsAction>(*set, linked_card, _(""), _(""), linked_card->findUIDLink(selected_card->uid)));
set->actions.addAction(make_unique<BulkAction>(actions, set, this), false);
return true;
}
+1 -1
View File
@@ -105,7 +105,7 @@ public:
bool canLink() const;
bool doLink();
bool doUnlink(CardP unlinked_card);
bool doUnlink(CardP linked_card);
// --------------------------------------------------- : Set actions
+3 -3
View File
@@ -36,11 +36,11 @@ void PrintJob::measure_cards() {
FOR_EACH(card, cards) {
if (already_measured_cards.find(card) != already_measured_cards.end()) continue;
already_measured_cards.emplace(card);
card_layouts.push_back(measure_card(card));
CardP other_face = card->getLinkedOtherFace(cards);
card_layouts.emplace_back(measure_card(card));
CardP other_face = card->getLinkedOtherFaceCard(cards);
if (other_face && already_measured_cards.find(other_face) == already_measured_cards.end()) {
already_measured_cards.emplace(other_face);
card_layouts.push_back(measure_card(other_face));
card_layouts.emplace_back(measure_card(other_face));
int index = card_layouts.size()-1;
card_layouts[index].other_face = index-1;
card_layouts[index-1].other_face = index;
+15 -15
View File
@@ -776,7 +776,7 @@ SCRIPT_FUNCTION(get_card_export_settings) {
SCRIPT_FUNCTION(get_card_from_uid) {
SCRIPT_PARAM_C(Set*, set);
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(Card::getCardFromUid(*set, input));
SCRIPT_RETURN(Card::getUIDCard(*set, input));
}
SCRIPT_FUNCTION(get_cards_from_link) {
@@ -787,7 +787,7 @@ SCRIPT_FUNCTION(get_cards_from_link) {
input_card = ic->getValue();
}
else if (input->type() == SCRIPT_STRING) {
input_card = Card::getCardFromUid(*set, input->toString());
input_card = Card::getUIDCard(*set, input->toString());
}
if (!input_card) {
queue_message(MESSAGE_ERROR, _ERROR_("could not find input"));
@@ -795,14 +795,14 @@ SCRIPT_FUNCTION(get_cards_from_link) {
}
SCRIPT_PARAM(String, linked_relation);
ScriptCustomCollectionP ret(new ScriptCustomCollection());
vector<CardP> other_cards = input_card->getLinkedCardsFromLink(*set, linked_relation, true);
vector<CardP> other_cards = input_card->getLinkedRelationCards(*set, linked_relation);
if (other_cards.size() > 0) {
FOR_EACH(other_card, other_cards) {
ret->value.push_back(to_script(other_card));
}
}
else if (set->game->card_links_alt_names.find(linked_relation) != set->game->card_links_alt_names.end()) {
other_cards = input_card->getLinkedCardsFromLink(*set, set->game->card_links_alt_names[linked_relation], true);
other_cards = input_card->getLinkedRelationCards(*set, set->game->card_links_alt_names[linked_relation]);
FOR_EACH(other_card, other_cards) {
ret->value.push_back(to_script(other_card));
}
@@ -818,13 +818,13 @@ SCRIPT_FUNCTION(get_front_face) {
input_card = ic->getValue();
}
else if (input->type() == SCRIPT_STRING) {
input_card = Card::getCardFromUid(*set, input->toString());
input_card = Card::getUIDCard(*set, input->toString());
}
if (!input_card) {
queue_message(MESSAGE_ERROR, _ERROR_("could not find input"));
return script_nil;
}
vector<CardP> other_cards = input_card->getLinkedCardsFromLink(*set, "Front Face", true);
vector<CardP> other_cards = input_card->getLinkedRelationCards(*set, "Front Face");
if (other_cards.size() == 0) return script_nil;
if (other_cards.size() > 1) queue_message(MESSAGE_WARNING, _ERROR_1_("multiple front faces", input_card->identification()));
SCRIPT_RETURN(other_cards[0]);
@@ -838,13 +838,13 @@ SCRIPT_FUNCTION(get_back_face) {
input_card = ic->getValue();
}
else if (input->type() == SCRIPT_STRING) {
input_card = Card::getCardFromUid(*set, input->toString());
input_card = Card::getUIDCard(*set, input->toString());
}
if (!input_card) {
queue_message(MESSAGE_ERROR, _ERROR_("could not find input"));
return script_nil;
}
vector<CardP> other_cards = input_card->getLinkedCardsFromLink(*set, "Back Face", true);
vector<CardP> other_cards = input_card->getLinkedRelationCards(*set, "Back Face");
if (other_cards.size() == 0) return script_nil;
if (other_cards.size() > 1) queue_message(MESSAGE_WARNING, _ERROR_1_("multiple back faces", input_card->identification()));
SCRIPT_RETURN(other_cards[0]);
@@ -858,7 +858,7 @@ SCRIPT_FUNCTION(add_link) {
input_card = ic->getValue();
}
else if (input->type() == SCRIPT_STRING) {
input_card = Card::getCardFromUid(*set, input->toString());
input_card = Card::getUIDCard(*set, input->toString());
}
if (!input_card) {
queue_message(MESSAGE_ERROR, _ERROR_("could not find input"));
@@ -870,7 +870,7 @@ SCRIPT_FUNCTION(add_link) {
other_card = c->getValue();
}
else if (linked_card->type() == SCRIPT_STRING) {
other_card = Card::getCardFromUid(*set, linked_card->toString());
other_card = Card::getUIDCard(*set, linked_card->toString());
}
if (!other_card) {
queue_message(MESSAGE_WARNING, _ERROR_("could not find linked"));
@@ -878,7 +878,7 @@ SCRIPT_FUNCTION(add_link) {
}
SCRIPT_PARAM(String, selected_relation);
SCRIPT_PARAM(String, linked_relation);
input_card->link(*set, other_card, selected_relation, linked_relation);
input_card->addLink(*set, other_card, selected_relation, linked_relation);
SCRIPT_RETURN(other_card);
}
@@ -891,7 +891,7 @@ SCRIPT_FUNCTION(remove_links) {
input_card = ic->getValue();
}
else if (input->type() == SCRIPT_STRING) {
input_card = Card::getCardFromUid(*set, input->toString());
input_card = Card::getUIDCard(*set, input->toString());
}
if (!input_card) {
queue_message(MESSAGE_ERROR, _ERROR_("could not find input"));
@@ -905,7 +905,7 @@ SCRIPT_FUNCTION(remove_links) {
other_card = c->getValue();
}
else if (linked_card->type() == SCRIPT_STRING) {
other_card = Card::getCardFromUid(*set, linked_card->toString());
other_card = Card::getUIDCard(*set, linked_card->toString());
}
if (!other_card) {
queue_message(MESSAGE_WARNING, _ERROR_("could not find linked"));
@@ -915,12 +915,12 @@ SCRIPT_FUNCTION(remove_links) {
SCRIPT_PARAM_DEFAULT(ScriptValueP, linked_relation, script_nil);
if (linked_relation != script_nil) {
if (linked_relation->type() == SCRIPT_STRING) {
vector<CardP> other_other_cards = input_card->getLinkedCardsFromLink(*set, linked_relation->toString(), true);
vector<CardP> other_other_cards = input_card->getLinkedRelationCards(*set, linked_relation->toString());
other_cards.insert(other_cards.end(), other_other_cards.begin(), other_other_cards.end());
}
}
input_card->unlink(other_cards);
FOR_EACH(other_card, other_cards) {
input_card->removeLink(other_card);
ret->value.push_back(to_script(other_card));
}
return ret;
+2 -2
View File
@@ -145,8 +145,8 @@ SCRIPT_FUNCTION(add_card_to_set) {
Set& _set = *s->getValue();
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(input.get());
if (c) {
CardP _card = c->getValue();
_set.actions.addAction(make_unique<AddCardAction>(ADD, _set, _card));
vector<CardP> _cards { c->getValue() };
_set.actions.addAction(make_unique<AddCardAction>(ADD, _set, _cards));
SCRIPT_RETURN(true);
}
if (input->type() == SCRIPT_COLLECTION) {
+3 -1
View File
@@ -12,13 +12,15 @@
#include <util/string.hpp>
#include <vector>
DECLARE_POINTER_TYPE(Action);
// ----------------------------------------------------------------------------- : Action
/// Base class for actions that can be stored in an ActionStack.
/** An action is something that can be done to modify an object.
* It must store the necessary information to also undo the action.
*/
class Action {
class Action : public IntrusivePtrVirtualBase, public IntrusiveFromThis<Action> {
public:
virtual ~Action() {};