Most maps grow into the same shape: a HeroName array, a HeroUnit array, a HeroSlot array, a HeroInitRank array and two more for rank increments. Adding one hero means editing six places together, and nothing checks that the six stayed in step.
epScript can run Python at compile time, so the data can be written once as a list of dictionaries and the arrays generated from it.
const HERO_DATA = py_eval('[ \
{"name": "손책", "unit": 48, "slot": 0, "ranks": [1321, 1322, 1323]}, \
{"name": "황개", "unit": 23, "slot": 1, "ranks": [1304, 1307, 1310]}, \
]');
const HERO_COUNT = py_len(HERO_DATA);
const HeroNames = EUDArray(py_eval('[EPD(Db(x["name"])) for x in HERO_DATA]'));
const HERO_UNITS = py_list(py_map(py_eval('lambda x: x["unit"]'), HERO_DATA));
const HeroUnitTypes = EUDArray(HERO_UNITS);
const HeroSlots = EUDArray(py_eval('[x["slot"] for x in HERO_DATA]'));And the part most worth taking even if you keep your arrays as they are comes next: a rule your data has to satisfy can be made into a compile error.
py_assert(HERO_COUNT == py_len(py_set(HERO_UNITS)), "영웅 유닛 중복");
py_assert(py_eval('all(len(x["ranks"]) == 1+MAX_RANK for x in HERO_DATA)'), "계급 개수 불일치");
py_assert(py_eval('all(0 <= x["slot"] < SLOT_COUNT for x in HERO_DATA)'), "슬롯 범위 초과");It is the counterpart of ep_assert, which proves a property of the code - “this construct emits no triggers”. py_assert checks that your data makes sense.
Packing several small values into one cell is also a compile-time job, and it removes two of the three arrays.
const HeroRankData = EUDArray(py_eval(
'[(x["ranks"][0] - 1302) + ((x["ranks"][1] - 1302) << 8)'
' + ((x["ranks"][2] - 1302) << 16) for x in HERO_DATA]'));
const rank = bread_epd(HeroRankData + heroIndex, currentRank); // currentRank번째 바이트When a whole data table has to be swapped - a game mode, say - give the variable an array type and repoint it.
var HeroRanksData: EUDArray = HeroRankDataMod0; // ... HeroRanksData = HeroRankDataMod1; // 표 전체를 교체 / swap the whole table for (var i = 0; i < HERO_COUNT; i += 1) updateHeroRank(i);
For an array of units, type the EUDVArray as CUnit. What comes out is a CUnit, the offset arithmetic disappears, and the death check reads like the sentence it is.
const HeroCUnit = EUDVArray(HERO_COUNT, CUnit)();
foreach(hero : HeroCUnit) {
if (hero == 0) continue;
if (hero.hp <= 0) hero.order = "Die"; // 먼저 / first
if (hero.order == "Die") { /* ... */ } // 그 다음 / then
}