mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
working on an improved random pack system, #ifdefed out for now
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1245 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
#include <data/game.hpp>
|
||||
#include <data/card.hpp>
|
||||
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
// =================================================================================================== OLD
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(PackItemRefP);
|
||||
DECLARE_TYPEOF_COLLECTION(PackItemP);
|
||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||
@@ -148,3 +151,422 @@ vector<CardP>& PackItemCache::cardsFor(const String& name) {
|
||||
throw Error(_ERROR_1_("pack item not found",name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
// =================================================================================================== NEW
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(PackTypeP);
|
||||
DECLARE_TYPEOF_COLLECTION(PackItemP);
|
||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackType
|
||||
|
||||
PackType::PackType()
|
||||
: enabled(true)
|
||||
, selectable(true)
|
||||
, summary(true)
|
||||
, select(SELECT_ALL)
|
||||
{}
|
||||
|
||||
IMPLEMENT_REFLECTION_ENUM(OneMany) {
|
||||
VALUE_N("all", SELECT_ALL);
|
||||
VALUE_N("at most one", SELECT_ONE_OR_EMPTY);
|
||||
VALUE_N("one", SELECT_ONE);
|
||||
VALUE_N("first", SELECT_FIRST);
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(PackType) {
|
||||
REFLECT(name);
|
||||
REFLECT(enabled);
|
||||
REFLECT(selectable);
|
||||
REFLECT(summary);
|
||||
REFLECT(select);
|
||||
REFLECT(cards);
|
||||
REFLECT(items);
|
||||
}
|
||||
|
||||
bool PackType::update(Context& ctx) {
|
||||
bool change = enabled.update(ctx);
|
||||
FOR_EACH(item, items) {
|
||||
change |= item->update(ctx);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackItem
|
||||
|
||||
PackItem::PackItem()
|
||||
: amount(1)
|
||||
, type(PACK_REF_INHERIT)
|
||||
{}
|
||||
|
||||
IMPLEMENT_REFLECTION_ENUM(PackSelectType) {
|
||||
VALUE_N("inherit", PACK_REF_INHERIT);
|
||||
VALUE_N("replace", PACK_REF_REPLACE);
|
||||
VALUE_N("no replace", PACK_REF_NO_REPLACE);
|
||||
VALUE_N("cyclic", PACK_REF_CYCLIC);
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(PackItem) {
|
||||
REFLECT(pack);
|
||||
REFLECT(amount);
|
||||
REFLECT(type);
|
||||
}
|
||||
|
||||
bool PackItem::update(Context& ctx) {
|
||||
return amount.update(ctx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackItemCache
|
||||
|
||||
ScriptValueP PackItemCache::cardsFor(const ScriptValueP& generate) {
|
||||
// lookup name
|
||||
ScriptValueP& value = item_cards[generate];
|
||||
if (!value) {
|
||||
value = generate->eval(set.getContext());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
const PackType& PackItemCache::pack(const String& name) {
|
||||
// not used before, generate list and cache
|
||||
FOR_EACH(pack, set.game->pack_types) {
|
||||
if (pack->name == name) {
|
||||
return *pack;
|
||||
}
|
||||
}
|
||||
// not found
|
||||
throw Error(_ERROR_1_("pack type not found", name));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Counting expected cards
|
||||
|
||||
double PackItemCounter::probabilityNonEmpty(const PackType& pack) {
|
||||
// TODO: cache?
|
||||
if (pack.cards) {
|
||||
return cardsFor(pack.cards.getScriptP())->itemCount();
|
||||
} else if (pack.select == SELECT_ONE_OR_EMPTY) {
|
||||
// weighted avarage
|
||||
double p = 0.0;
|
||||
double total_weight = 0.0;
|
||||
FOR_EACH_CONST(i,pack.items) {
|
||||
p += i->weight * probabilityNonEmpty(*i);
|
||||
total_weight += i->weight;
|
||||
}
|
||||
return p / total_weight;
|
||||
} else { // SELECT_ONE, SELECT_FIRST, SELECT_ALL
|
||||
// disjunction
|
||||
double p = 0.0;
|
||||
FOR_EACH_CONST(i,pack.items) {
|
||||
// either already non-empty, or all previous items were empty so pick this one
|
||||
p += (1-p) * probabilityNonEmpty(*i);
|
||||
if (p >= 1 - 1e-6) return 1.0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
double PackItemCounter::probabilityNonEmpty(const PackItem& item) {
|
||||
return item.amount <= 0 ? 0 : probabilityNonEmpty(pack(item.pack));
|
||||
}
|
||||
|
||||
void PackItemCounter::addCountRecursive(const PackType& pack, double copies) {
|
||||
// add
|
||||
counts[&pack] += copies * probabilityNonEmpty(pack);
|
||||
// recurse
|
||||
if (pack.cards) {
|
||||
// done
|
||||
} else if (pack.select == SELECT_FIRST) {
|
||||
double p = 1;
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
addCountRecursive(*i, p * copies);
|
||||
p *= 1 - probabilityNonEmpty(*i);
|
||||
if (p < 1e-6) return;
|
||||
}
|
||||
} else if (pack.select == SELECT_ONE_OR_EMPTY || pack.select == SELECT_ONE) {
|
||||
double total_weight = 0.0;
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
total_weight += i->weight * (pack.select == SELECT_ONE ? probabilityNonEmpty(*i) : 1.0);
|
||||
}
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
addCountRecursive(*i, copies * i->weight / total_weight);
|
||||
}
|
||||
} else if (pack.select == SELECT_ALL) {
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
addCountRecursive(*i, copies);
|
||||
}
|
||||
} else {
|
||||
throw InternalError(_("unknown OneMany value"));
|
||||
}
|
||||
}
|
||||
|
||||
void PackItemCounter::addCountRecursive(const PackItem& item, double copies) {
|
||||
addCountRecursive(pack(item.pack), item.amount * copies);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Generating
|
||||
|
||||
DECLARE_TYPEOF(PackItemGenerator::OfTypeCount);
|
||||
|
||||
/// Random generator with random numbers in a range
|
||||
template <typename Gen>
|
||||
struct RandomRange {
|
||||
RandomRange(Gen& gen) : gen(gen) {}
|
||||
unsigned operator () (unsigned max) { return gen() % max; }
|
||||
Gen& gen;
|
||||
};
|
||||
|
||||
bool PackItemGenerator::generateCount(const PackType& pack, int copies, PackSelectType type, OfTypeCount& out) {
|
||||
if (copies <= 0) return false;
|
||||
bool non_empty = false;
|
||||
if (pack.cards) {
|
||||
ScriptValueP the_cards = cardsFor(pack.cards.getScriptP());
|
||||
non_empty = the_cards->itemCount() > 0;
|
||||
if (non_empty) {
|
||||
out[make_pair(the_cards,type)] += copies;
|
||||
}
|
||||
} else if (pack.select == SELECT_ALL) {
|
||||
// just generate all
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
non_empty |= generateCount(*i, 1, type, out);
|
||||
}
|
||||
} else {
|
||||
// generate each copy separately
|
||||
for (int j = 0 ; j < copies ; ++j) {
|
||||
non_empty |= generateSingleCount(pack, type, out);
|
||||
}
|
||||
}
|
||||
return non_empty;
|
||||
}
|
||||
|
||||
bool PackItemGenerator::generateSingleCount(const PackType& pack, PackSelectType type, OfTypeCount& out) {
|
||||
if (pack.select == SELECT_ONE_OR_EMPTY) {
|
||||
// pick a random item by weight
|
||||
double total_weight = 0.0;
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
total_weight += i->weight;
|
||||
}
|
||||
double choice = gen() * total_weight / gen.max();
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
if ((choice -= i->weight) <= 0) {
|
||||
// pick this one
|
||||
return generateCount(*i, 1, type, out);
|
||||
}
|
||||
}
|
||||
} else if (pack.select == SELECT_ONE) {
|
||||
// pick a random item by weight that is not empty
|
||||
UInt possible = 0; // bitmask
|
||||
double total_weight = 0.0;
|
||||
for (size_t i = 0 ; i < pack.items.size() ; ++i) {
|
||||
total_weight += pack.items[i]->weight;
|
||||
possible |= 1 << i;
|
||||
}
|
||||
while (possible) {
|
||||
// try to make a choice we have not made before
|
||||
int choice = gen() * total_weight / gen.max();
|
||||
for (size_t i = 0 ; i < pack.items.size() ; ++i) {
|
||||
const PackItem& item = *pack.items[i];
|
||||
if (!(possible & (1<<i))) continue; // already tried this item?
|
||||
if ((choice -= item.weight) <= 0) {
|
||||
bool non_empty = generateCount(item, 1, type, out);
|
||||
if (non_empty) {
|
||||
// found a non-empty choice, done
|
||||
return true;
|
||||
} else {
|
||||
// try again, exclude this item
|
||||
possible &= ~(1 << i);
|
||||
total_weight -= item.weight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (pack.select == SELECT_FIRST) {
|
||||
// pick the first one that is not empty
|
||||
FOR_EACH_CONST(i, pack.items) {
|
||||
bool non_empty = generateCount(*i, 1, type, out);
|
||||
if (non_empty) return true;
|
||||
}
|
||||
} else {
|
||||
throw InternalError(_("unknown OneMany value"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool PackItemGenerator::generateCount(const PackItem& item, int copies, PackSelectType type, OfTypeCount& out) {
|
||||
return generateCount(pack(item.pack), copies * item.amount, item.type == PACK_REF_INHERIT ? type : item.type, out);
|
||||
}
|
||||
|
||||
void PackItemGenerator::generate(const PackType& pack) {
|
||||
// first determine how many cards of each basic type we need
|
||||
OfTypeCount counts;
|
||||
generateCount(pack, 1, PACK_REF_NO_REPLACE, counts);
|
||||
// now select these cards
|
||||
FOR_EACH(c, counts) {
|
||||
pickCards(c.first.first, c.first.second, c.second);
|
||||
}
|
||||
}
|
||||
void PackItemGenerator::pickCards(const ScriptValueP& cards, PackSelectType type, int amount) {
|
||||
// generate 'amount' cards and add them to out
|
||||
int cards_size = cards->itemCount();
|
||||
if (cards_size <= 0) return;
|
||||
RandomRange<boost::mt19937> gen_range(gen);
|
||||
if (type == PACK_REF_REPLACE) {
|
||||
// amount random numbers
|
||||
for (int i = 0 ; i < amount ; ++i) {
|
||||
int index = gen_range(cards_size);
|
||||
out.push_back(from_script<CardP>(cards->getIndex(index)));
|
||||
}
|
||||
} else if (type == PACK_REF_NO_REPLACE) {
|
||||
// random shuffle
|
||||
// to prevent us from being too predictable for small sets, periodically reshuffle
|
||||
int max_per_batch = (cards_size + 1) / 2;
|
||||
while (amount > 0) {
|
||||
int to_add = min(amount, max_per_batch);
|
||||
size_t old_out_size = out.size();
|
||||
// add all to output temporarily
|
||||
ScriptValueP it = cards->makeIterator(cards);
|
||||
while (ScriptValueP card = it->next()) {
|
||||
out.push_back(from_script<CardP>(card));
|
||||
}
|
||||
// shuffle and keep only the first to_add
|
||||
random_shuffle(out.begin() + old_out_size, out.end(), gen_range);
|
||||
out.resize(old_out_size + to_add);
|
||||
amount -= to_add;
|
||||
}
|
||||
} else if (type == PACK_REF_CYCLIC) {
|
||||
// multiple copies
|
||||
int copies = amount / cards_size;
|
||||
ScriptValueP it = cards->makeIterator(cards);
|
||||
while (ScriptValueP card = it->next()) {
|
||||
out.insert(out.end(), copies, from_script<CardP>(card));
|
||||
}
|
||||
amount -= copies * cards_size;
|
||||
// if amount is not a multiple of the number of cards, pick the rest at random
|
||||
for (int i = 0 ; i < amount ; ++i) {
|
||||
int index = gen_range(cards_size);
|
||||
out.push_back(from_script<CardP>(cards->getIndex(index)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*//%
|
||||
// ----------------------------------------------------------------------------- : PackItem
|
||||
|
||||
void PackItemCounter::count(const String& name, double amount) {
|
||||
map<PackItemRef*,double>::iterator it = sizes.find(name);
|
||||
if (it != sizes.end()) return it->second;
|
||||
|
||||
size *= amount * probability;
|
||||
return sizes[&item] = size;
|
||||
}
|
||||
void PackItemCounter::count(const PackType& pack, int copies) {
|
||||
double size = 0;
|
||||
if (pack.select = ONE) {
|
||||
double total_size;
|
||||
FOR_EACH(item, pack.items) {
|
||||
double item_size = size(item);
|
||||
if (item->type == OTHER_IF_EMPTY) {
|
||||
// is it empty?
|
||||
total_size += item_size > 0 ? 1 : 0;
|
||||
max_size += 1;
|
||||
} else if (item->type == WEIGHTED) {
|
||||
total_size += item_size;
|
||||
max_size += item_size;
|
||||
} else {
|
||||
total_size += 1;
|
||||
max_size += 1;
|
||||
}
|
||||
}
|
||||
size += total_size / max_size;
|
||||
// count
|
||||
FOR_EACH(item, pack.items) {
|
||||
double item_size = size(item);
|
||||
if (item_size > 0 && !item->cards) {
|
||||
if (item->type == OTHER_IF_EMPTY) {
|
||||
// is it empty?
|
||||
total_size += item_size > 0 ? 1 : 0;
|
||||
max_size += 1;
|
||||
} else if (item->type == WEIGHTED) {
|
||||
total_size += item_size;
|
||||
max_size += item_size;
|
||||
} else {
|
||||
total_size += 1;
|
||||
max_size += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // MANY
|
||||
|
||||
}
|
||||
amounts[pack.name] += amount;
|
||||
}
|
||||
double PackItemCounter::size(const String& name) {
|
||||
map<PackItemRef*,double>::iterator it = sizes.find(name);
|
||||
if (it != sizes.end()) return it->second;
|
||||
double the_size = 0;
|
||||
FOR_EACH() {
|
||||
the_size += size(item);
|
||||
}
|
||||
return sizes[&item] = the_size;
|
||||
}
|
||||
double PackItemCounter::size(const PackItemRef& item) {
|
||||
String the_name;
|
||||
double the_size;
|
||||
if (cards) {
|
||||
the_size = cards.invokeOn(ctx)->itemCount() > 0 ? 1 : 0;
|
||||
} else {
|
||||
the_size = size(name);
|
||||
the_name = name;
|
||||
}
|
||||
if (the_size == 0 && !if_empty.empty())
|
||||
the_name = if_empty;
|
||||
the_size = size(if_empty);
|
||||
}
|
||||
if (!the_name.empty()) {
|
||||
counts[the_name] += amount * probability;
|
||||
}
|
||||
return the_size * amount * probability;
|
||||
}
|
||||
|
||||
|
||||
void PackItemCounter::count(const PackType& pack, int copies, type) {
|
||||
if (pack.cards) {
|
||||
//
|
||||
cards =..
|
||||
if (!cards.empty()) {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackItem
|
||||
|
||||
IMPLEMENT_REFLECTION(PackItem) {
|
||||
REFLECT(name);
|
||||
REFLECT(filter);
|
||||
}
|
||||
|
||||
void PackItem::generate(Set& set, vector<CardP>& out) const {
|
||||
FOR_EACH(card, set.cards) {
|
||||
Context& ctx = set.getContext(card);
|
||||
bool keep = *filter.invoke(ctx);
|
||||
if (keep) {
|
||||
out.push_back(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackItemCache
|
||||
|
||||
PackItemCache::PackItemCache(Set& set)
|
||||
: set(set)
|
||||
{}*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
#include <script/scriptable.hpp>
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
|
||||
#define USE_NEW_PACK_SYSTEM 0
|
||||
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
// =================================================================================================== OLD
|
||||
|
||||
DECLARE_POINTER_TYPE(PackItemRef);
|
||||
DECLARE_POINTER_TYPE(Card);
|
||||
class Set;
|
||||
@@ -97,5 +102,152 @@ class PackItemCache {
|
||||
map<String,Cards> item_cards;
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
// =================================================================================================== NEW
|
||||
|
||||
DECLARE_POINTER_TYPE(PackItem);
|
||||
DECLARE_POINTER_TYPE(Card);
|
||||
class Set;
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackType
|
||||
|
||||
enum OneMany
|
||||
{ SELECT_ONE_OR_EMPTY
|
||||
, SELECT_ONE
|
||||
, SELECT_FIRST
|
||||
, SELECT_ALL
|
||||
};
|
||||
|
||||
/// A card pack description for playtesting
|
||||
class PackType : public IntrusivePtrBase<PackType> {
|
||||
public:
|
||||
PackType();
|
||||
|
||||
String name; ///< Name of this pack
|
||||
Scriptable<bool> enabled; ///< Is this pack enabled?
|
||||
bool selectable; ///< Is this pack listed in the UI?
|
||||
bool summary; ///< Should the total be listed for this type?
|
||||
OneMany select; ///< Select one or many?
|
||||
OptionalScript cards; ///< Script to select this type of cards (there are no items)
|
||||
OptionalScript filter; ///< Filter to select this type of cards
|
||||
vector<PackItemP> items; ///< Subpacks in this pack
|
||||
|
||||
/// Update scripts, returns true if there is a change
|
||||
bool update(Context& ctx);
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackItem
|
||||
|
||||
enum PackSelectType
|
||||
{ PACK_REF_INHERIT
|
||||
, PACK_REF_REPLACE
|
||||
, PACK_REF_NO_REPLACE
|
||||
, PACK_REF_CYCLIC
|
||||
};
|
||||
|
||||
/// An item in a PackType
|
||||
class PackItem : public IntrusivePtrBase<PackItem> {
|
||||
public:
|
||||
PackItem();
|
||||
|
||||
String pack; ///< Name of the pack to select cards from
|
||||
Scriptable<int> amount; ///< Number of cards of this type
|
||||
Scriptable<double> weight; ///< Relative probability of picking this item
|
||||
PackSelectType type;
|
||||
|
||||
/// Update scripts, returns true if there is a change
|
||||
bool update(Context& ctx);
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Generating / counting
|
||||
|
||||
// --------------------------------------------------- : PackItemCache
|
||||
|
||||
class PackItemCache {
|
||||
public:
|
||||
PackItemCache(Set& set) : set(set) {}
|
||||
|
||||
/// Look up a pack type by name
|
||||
const PackType& pack(const String& name);
|
||||
|
||||
protected:
|
||||
Set& set;
|
||||
|
||||
/// The cards for a given PackItem
|
||||
ScriptValueP cardsFor(const ScriptValueP& cards_script);
|
||||
|
||||
private:
|
||||
/// Lookup PackTypes by name
|
||||
//%%
|
||||
/// Cards for each PackType
|
||||
map<ScriptValueP,ScriptValueP> item_cards;
|
||||
};
|
||||
|
||||
// --------------------------------------------------- : Counting expected cards
|
||||
|
||||
/// Class for determining the *expected* number of cards from each type
|
||||
class PackItemCounter : PackItemCache {
|
||||
public:
|
||||
PackItemCounter(Set& set, map<const PackType*,double>& counts)
|
||||
: PackItemCache(set), counts(counts)
|
||||
{}
|
||||
|
||||
/// Add a number of copies of the PackType to the counts, recurse into child items
|
||||
void addCountRecursive(const PackType& pack, double copies);
|
||||
void addCountRecursive(const PackItem& item, double copies);
|
||||
|
||||
/// The probability that the given pack is non-empty
|
||||
double probabilityNonEmpty(const PackType& pack);
|
||||
double probabilityNonEmpty(const PackItem& item);
|
||||
|
||||
/// The counts will be stored here
|
||||
map<const PackType*,double>& counts;
|
||||
|
||||
private:
|
||||
/// The probability that a pack type is empty (cache)
|
||||
//%map<const PackItem*,double> probability_empty;
|
||||
};
|
||||
|
||||
// --------------------------------------------------- : PackItemCounter
|
||||
|
||||
/// Class for generating card packs
|
||||
class PackItemGenerator : PackItemCache {
|
||||
public:
|
||||
PackItemGenerator(Set& set, vector<CardP>& cards, boost::mt19937& gen)
|
||||
: PackItemCache(set), out(cards), gen(gen)
|
||||
{}
|
||||
|
||||
/// Generate a pack, adding it to cards
|
||||
void generate(const PackType& pack);
|
||||
|
||||
/// Number of cards of a type
|
||||
typedef map<pair<ScriptValueP,PackSelectType>,int> OfTypeCount;
|
||||
|
||||
/// Determine what *types* of cards to pick (store in out)
|
||||
/** Does NOT add cards yet.
|
||||
* Returns true if non-empty.
|
||||
*/
|
||||
bool generateCount(const PackType& pack, int copies, PackSelectType type, OfTypeCount& out);
|
||||
bool generateCount(const PackItem& item, int copies, PackSelectType type, OfTypeCount& out);
|
||||
bool generateSingleCount(const PackType& pack, PackSelectType type, OfTypeCount& out);
|
||||
|
||||
/// Pick cards from a list
|
||||
void pickCards(const ScriptValueP& cards, PackSelectType type, int amount);
|
||||
|
||||
/// The cards will be stored here
|
||||
vector<CardP>& out;
|
||||
|
||||
/// Random generator
|
||||
boost::mt19937& gen;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(PackTypeP);
|
||||
DECLARE_TYPEOF_COLLECTION(PackItemP);
|
||||
DECLARE_TYPEOF_COLLECTION(PackItemRefP);
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
DECLARE_TYPEOF_COLLECTION(PackItemRefP);
|
||||
#endif
|
||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||
DECLARE_TYPEOF_COLLECTION(RandomPackPanel::PackItem_for_typeof);
|
||||
|
||||
@@ -34,8 +36,10 @@ class RandomCardList : public CardListBase {
|
||||
|
||||
/// Reset the list
|
||||
void reset();
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
/// Add a pack of cards
|
||||
void add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack);
|
||||
#endif
|
||||
|
||||
using CardListBase::rebuild;
|
||||
|
||||
@@ -45,7 +49,11 @@ class RandomCardList : public CardListBase {
|
||||
virtual void getItems(vector<VoidP>& out) const;
|
||||
virtual void onChangeSet();
|
||||
|
||||
private:
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
public:
|
||||
#else
|
||||
private:
|
||||
#endif
|
||||
vector<CardP> cards;
|
||||
};
|
||||
|
||||
@@ -56,9 +64,12 @@ RandomCardList::RandomCardList(Window* parent, int id, long style)
|
||||
void RandomCardList::reset() {
|
||||
cards.clear();
|
||||
}
|
||||
void RandomCardList::add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack) {
|
||||
pack.generate(packs,gen,cards);
|
||||
}
|
||||
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
void RandomCardList::add(PackItemCache& packs, boost::mt19937& gen, const PackType& pack) {
|
||||
pack.generate(packs,gen,cards);
|
||||
}
|
||||
#endif
|
||||
|
||||
void RandomCardList::onChangeSet() {
|
||||
reset();
|
||||
@@ -80,15 +91,22 @@ class PackTotalsPanel : public wxPanel {
|
||||
PackTotalsPanel(Window* parent, int id) : wxPanel(parent,id) {}
|
||||
void setGame(const GameP& game);
|
||||
void clear();
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
void addPack(PackType& pack, int copies);
|
||||
void addItemRef(PackItemRef& item, int copies);
|
||||
#endif
|
||||
private:
|
||||
DECLARE_EVENT_TABLE();
|
||||
GameP game;
|
||||
void onPaint(wxPaintEvent&);
|
||||
void draw(DC& dc);
|
||||
void drawItem(DC& dc, int& y, const String& name, int value);
|
||||
void drawItem(DC& dc, int& y, const String& name, double value);
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
public:
|
||||
map<const PackType*,double> amounts;
|
||||
#else
|
||||
map<String,int> amounts;
|
||||
#endif
|
||||
};
|
||||
|
||||
void PackTotalsPanel::onPaint(wxPaintEvent&) {
|
||||
@@ -106,11 +124,21 @@ void PackTotalsPanel::draw(DC& dc) {
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
int y = 0;
|
||||
int total = 0;
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
FOR_EACH(pack, game->pack_types) {
|
||||
if (pack->summary) {
|
||||
int value = amounts[pack.get()];
|
||||
drawItem(dc, y, tr(*game, pack->name, capitalize), value);
|
||||
total += value;
|
||||
}
|
||||
}
|
||||
#else
|
||||
FOR_EACH(item, game->pack_items) {
|
||||
int value = amounts[item->name];
|
||||
drawItem(dc, y, tr(*game, item->name, capitalize), value);
|
||||
total += value;
|
||||
}
|
||||
#endif
|
||||
// draw total
|
||||
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
|
||||
dc.DrawLine(0, y-3, size.x, y-3);
|
||||
@@ -120,10 +148,10 @@ void PackTotalsPanel::draw(DC& dc) {
|
||||
drawItem(dc, y, _LABEL_("total cards"), total);
|
||||
|
||||
}
|
||||
void PackTotalsPanel::drawItem(DC& dc, int& y, const String& name, int value) {
|
||||
void PackTotalsPanel::drawItem(DC& dc, int& y, const String& name, double value) {
|
||||
wxSize size = dc.GetSize();
|
||||
int w,h;
|
||||
String amount; amount << value;
|
||||
String amount = String::Format(_("%.f"),value);
|
||||
dc.GetTextExtent(amount,&w,&h);
|
||||
dc.DrawText(name, 0, y);
|
||||
dc.DrawText(amount, size.x-w, y);//align right
|
||||
@@ -137,14 +165,16 @@ void PackTotalsPanel::setGame(const GameP& game) {
|
||||
void PackTotalsPanel::clear() {
|
||||
amounts.clear();
|
||||
}
|
||||
void PackTotalsPanel::addPack(PackType& pack, int copies) {
|
||||
FOR_EACH(item,pack.items) {
|
||||
addItemRef(*item, copies * item->amount);
|
||||
#if !USE_NEW_PACK_SYSTEM
|
||||
void PackTotalsPanel::addPack(PackType& pack, int copies) {
|
||||
FOR_EACH(item,pack.items) {
|
||||
addItemRef(*item, copies * item->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
void PackTotalsPanel::addItemRef(PackItemRef& item, int copies) {
|
||||
amounts[item.name] += copies;
|
||||
}
|
||||
void PackTotalsPanel::addItemRef(PackItemRef& item, int copies) {
|
||||
amounts[item.name] += copies;
|
||||
}
|
||||
#endif
|
||||
|
||||
BEGIN_EVENT_TABLE(PackTotalsPanel, wxPanel)
|
||||
EVT_PAINT(PackTotalsPanel::onPaint)
|
||||
@@ -298,12 +328,19 @@ void RandomPackPanel::onCommand(int id) {
|
||||
// ----------------------------------------------------------------------------- : Generating
|
||||
|
||||
void RandomPackPanel::updateTotals() {
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
PackItemCounter counter(*set, totals->amounts);
|
||||
#endif
|
||||
totals->clear();
|
||||
total_packs = 0;
|
||||
FOR_EACH(i,packs) {
|
||||
int copies = i.value->GetValue();
|
||||
total_packs += copies;
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
counter.addCountRecursive(*i.pack, copies);
|
||||
#else
|
||||
totals->addPack(*i.pack, copies);
|
||||
#endif
|
||||
}
|
||||
// update UI
|
||||
totals->Refresh(false);
|
||||
@@ -337,13 +374,21 @@ void RandomPackPanel::setSeed(int seed) {
|
||||
|
||||
void RandomPackPanel::generate() {
|
||||
boost::mt19937 gen((unsigned)getSeed());
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
PackItemGenerator generator(*set, card_list->cards, gen);
|
||||
#else
|
||||
PackItemCache pack_cache(*set);
|
||||
#endif
|
||||
// add packs to card list
|
||||
card_list->reset();
|
||||
FOR_EACH(item,packs) {
|
||||
int copies = item.value->GetValue();
|
||||
for (int i = 0 ; i < copies ; ++i) {
|
||||
#if USE_NEW_PACK_SYSTEM
|
||||
generator.generate(*item.pack);
|
||||
#else
|
||||
card_list->add(pack_cache, gen, *item.pack);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
card_list->rebuild();
|
||||
|
||||
Reference in New Issue
Block a user