/* virtual */ bool COrder_SpellCast::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { if (!strcmp(value, "spell")) { ++j; lua_rawgeti(l, -1, j + 1); this->Spell = SpellTypeByIdent(LuaToString(l, -1)); lua_pop(l, 1); } else if (!strcmp(value, "range")) { ++j; lua_rawgeti(l, -1, j + 1); this->Range = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "state")) { ++j; lua_rawgeti(l, -1, j + 1); this->State = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "tile")) { ++j; lua_rawgeti(l, -1, j + 1); CclGetPos(l, &this->goalPos.x , &this->goalPos.y); lua_pop(l, 1); } else { return false; } return true; }
/** ** Parse Spell. ** ** @param l Lua state. */ static int CclDefineSpell(lua_State *l) { const int args = lua_gettop(l); const std::string identname = LuaToString(l, 1); SpellType *spell = SpellTypeByIdent(identname); if (spell != NULL) { DebugPrint("Redefining spell-type `%s'\n" _C_ identname.c_str()); } else { spell = new SpellType(SpellTypeTable.size(), identname); for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) { // adjust array for caster already defined if (UnitTypes[i]->CanCastSpell) { char *newc = new char[(SpellTypeTable.size() + 1) * sizeof(char)]; memcpy(newc, UnitTypes[i]->CanCastSpell, SpellTypeTable.size() * sizeof(char)); delete[] UnitTypes[i]->CanCastSpell; UnitTypes[i]->CanCastSpell = newc; UnitTypes[i]->CanCastSpell[SpellTypeTable.size()] = 0; } if (UnitTypes[i]->AutoCastActive) { char *newc = new char[(SpellTypeTable.size() + 1) * sizeof(char)]; memcpy(newc, UnitTypes[i]->AutoCastActive, SpellTypeTable.size() * sizeof(char)); delete[] UnitTypes[i]->AutoCastActive; UnitTypes[i]->AutoCastActive = newc; UnitTypes[i]->AutoCastActive[SpellTypeTable.size()] = 0; } } SpellTypeTable.push_back(spell); } for (int i = 1; i < args; ++i) { const char *value = LuaToString(l, i + 1); ++i; if (!strcmp(value, "showname")) { spell->Name = LuaToString(l, i + 1); } else if (!strcmp(value, "manacost")) { spell->ManaCost = LuaToNumber(l, i + 1); } else if (!strcmp(value, "range")) { if (!lua_isstring(l, i + 1) && !lua_isnumber(l, i + 1)) { LuaError(l, "incorrect argument"); } if (lua_isstring(l, i + 1) && !strcmp(lua_tostring(l, i + 1), "infinite")) { spell->Range = INFINITE_RANGE; } else if (lua_isnumber(l, i + 1)) { spell->Range = static_cast<int>(lua_tonumber(l, i + 1)); } else { LuaError(l, "Invalid range"); } } else if (!strcmp(value, "repeat-cast")) { spell->RepeatCast = 1; --i; } else if (!strcmp(value, "target")) { value = LuaToString(l, i + 1); if (!strcmp(value, "self")) { spell->Target = TargetSelf; } else if (!strcmp(value, "unit")) { spell->Target = TargetUnit; } else if (!strcmp(value, "position")) { spell->Target = TargetPosition; } else { LuaError(l, "Unsupported spell target type tag: %s" _C_ value); } } else if (!strcmp(value, "action")) { if (!lua_istable(l, i + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, i + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, i + 1, k + 1); spell->Action.push_back(CclSpellAction(l)); lua_pop(l, 1); } } else if (!strcmp(value, "condition")) { if (!spell->Condition) { spell->Condition = new ConditionInfo; } lua_pushvalue(l, i + 1); CclSpellCondition(l, spell->Condition); lua_pop(l, 1); } else if (!strcmp(value, "autocast")) { if (!spell->AutoCast) { spell->AutoCast = new AutoCastInfo(); } lua_pushvalue(l, i + 1); CclSpellAutocast(l, spell->AutoCast); lua_pop(l, 1); } else if (!strcmp(value, "ai-cast")) { if (!spell->AICast) { spell->AICast = new AutoCastInfo(); } lua_pushvalue(l, i + 1); CclSpellAutocast(l, spell->AICast); lua_pop(l, 1); } else if (!strcmp(value, "sound-when-cast")) { // Free the old name, get the new one spell->SoundWhenCast.Name = LuaToString(l, i + 1); spell->SoundWhenCast.MapSound(); // Check for sound. if (!spell->SoundWhenCast.Sound) { spell->SoundWhenCast.Name.clear(); } } else if (!strcmp(value, "depend-upgrade")) { value = LuaToString(l, i + 1); spell->DependencyId = UpgradeIdByIdent(value); if (spell->DependencyId == -1) { lua_pushfstring(l, "Bad upgrade name: %s", value); } } else { LuaError(l, "Unsupported tag: %s" _C_ value); } } return 0; }
int ParseAnimInt(const CUnit &unit, const char *parseint) { char s[100]; const CUnit *goal = &unit; if (!strlen(parseint)) { return 0; } strcpy(s, parseint); char *cur = &s[2]; if (s[0] == 'v' || s[0] == 't') { //unit variable detected if (s[0] == 't') { if (unit.CurrentOrder()->HasGoal()) { goal = unit.CurrentOrder()->GetGoal(); } else { return 0; } } char *next = strchr(cur, '.'); if (next == NULL) { fprintf(stderr, "Need also specify the variable '%s' tag \n", cur); ExitFatal(1); } else { *next = '\0'; } const int index = UnitTypeVar.VariableNameLookup[cur];// User variables if (index == -1) { if (!strcmp(cur, "ResourcesHeld")) { return goal->ResourcesHeld; } else if (!strcmp(cur, "ResourceActive")) { return goal->Resource.Active; } else if (!strcmp(cur, "_Distance")) { return unit.MapDistanceTo(*goal); } fprintf(stderr, "Bad variable name '%s'\n", cur); ExitFatal(1); } if (!strcmp(next + 1, "Value")) { return goal->Variable[index].Value; } else if (!strcmp(next + 1, "Max")) { return goal->Variable[index].Max; } else if (!strcmp(next + 1, "Increase")) { return goal->Variable[index].Increase; } else if (!strcmp(next + 1, "Enable")) { return goal->Variable[index].Enable; } else if (!strcmp(next + 1, "Percent")) { return goal->Variable[index].Value * 100 / goal->Variable[index].Max; } return 0; } else if (s[0] == 'b' || s[0] == 'g') { //unit bool flag detected if (s[0] == 'g') { if (unit.CurrentOrder()->HasGoal()) { goal = unit.CurrentOrder()->GetGoal(); } else { return 0; } } const int index = UnitTypeVar.BoolFlagNameLookup[cur];// User bool flags if (index == -1) { fprintf(stderr, "Bad bool-flag name '%s'\n", cur); ExitFatal(1); } return goal->Type->BoolFlag[index].value; } else if (s[0] == 's') { //spell type detected Assert(goal->CurrentAction() == UnitActionSpellCast); const COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder()); const SpellType &spell = order.GetSpell(); if (!strcmp(spell.Ident.c_str(), cur)) { return 1; } return 0; } else if (s[0] == 'S') { // check if autocast for this spell available const SpellType *spell = SpellTypeByIdent(cur); if (!spell) { fprintf(stderr, "Invalid spell: '%s'\n", cur); ExitFatal(1); } if (unit.AutoCastSpell[spell->Slot]) { return 1; } return 0; } else if (s[0] == 'p') { //player variable detected char *next; if (*cur == '(') { ++cur; char *end = strchr(cur, ')'); if (end == NULL) { fprintf(stderr, "ParseAnimInt: expected ')'\n"); ExitFatal(1); } *end = '\0'; next = end + 1; } else { next = strchr(cur, '.'); } if (next == NULL) { fprintf(stderr, "Need also specify the %s player's property\n", cur); ExitFatal(1); } else { *next = '\0'; } char *arg = strchr(next + 1, '.'); if (arg != NULL) { *arg = '\0'; } return GetPlayerData(ParseAnimPlayer(unit, cur), next + 1, arg + 1); } else if (s[0] == 'r') { //random value char *next = strchr(cur, '.'); if (next == NULL) { return SyncRand(atoi(cur) + 1); } else { *next = '\0'; const int min = atoi(cur); return min + SyncRand(atoi(next + 1) - min + 1); } } else if (s[0] == 'l') { //player number return ParseAnimPlayer(unit, cur); } // Check if we trying to parse a number Assert(isdigit(s[0]) || s[0] == '-'); return atoi(parseint); }
/** ** FIXME: docu */ int AddButton(int pos, int level, const std::string &icon_ident, ButtonCmd action, const std::string &value, void* actionCb, const ButtonCheckFunc func, const std::string &allow, const int key, const std::string &hint, const std::string &descr, const std::string &sound, const std::string &cursor, const std::string &umask, const std::string &popup, bool alwaysShow) { char buf[2048]; ButtonAction *ba = new ButtonAction; Assert(ba); ba->Pos = pos; ba->Level = level; ba->AlwaysShow = alwaysShow; ba->Icon.Name = icon_ident; ba->Payload = actionCb; // FIXME: check if already initited //ba->Icon.Load(); ba->Action = action; if (!value.empty()) { ba->ValueStr = value; switch (action) { case ButtonSpellCast: ba->Value = SpellTypeByIdent(value)->Slot; #ifdef DEBUG if (ba->Value < 0) { DebugPrint("Spell %s does not exist?\n" _C_ value.c_str()); Assert(ba->Value >= 0); } #endif break; case ButtonTrain: ba->Value = UnitTypeIdByIdent(value); break; case ButtonResearch: ba->Value = UpgradeIdByIdent(value); break; case ButtonUpgradeTo: ba->Value = UnitTypeIdByIdent(value); break; case ButtonBuild: ba->Value = UnitTypeIdByIdent(value); break; default: ba->Value = atoi(value.c_str()); break; } } else { ba->ValueStr.clear(); ba->Value = 0; } ba->Allowed = func; ba->AllowStr = allow; ba->Key = key; ba->Hint = hint; ba->Description = descr; ba->CommentSound.Name = sound; if (!ba->CommentSound.Name.empty()) { ba->CommentSound.MapSound(); } if (!ba->Popup.empty()) { CPopup *popup = PopupByIdent(ba->Popup); if (!popup) { fprintf(stderr, "Popup \"%s\" hasn't defined.\n ", ba->Popup.c_str()); Exit(1); } } ba->ButtonCursor = cursor; ba->Popup = popup; // FIXME: here should be added costs to the hint // FIXME: johns: show should be nice done? if (umask[0] == '*') { strcpy_s(buf, sizeof(buf), umask.c_str()); } else { sprintf(buf, ",%s,", umask.c_str()); } ba->UnitMask = buf; UnitButtonTable.push_back(ba); // FIXME: check if already initited //Assert(ba->Icon.Icon != NULL);// just checks, that's why at the end return 1; }
/** ** Parse unit ** ** @param l Lua state. ** ** @todo Verify that vision table is always correct (transporter) ** @todo (PlaceUnit() and host-info). */ static int CclUnit(lua_State *l) { const int slot = LuaToNumber(l, 1); if (!lua_istable(l, 2)) { LuaError(l, "incorrect argument"); } CUnit *unit = NULL; CUnitType *type = NULL; CUnitType *seentype = NULL; CPlayer *player = NULL; // Parse the list: const int args = lua_rawlen(l, 2); for (int j = 0; j < args; ++j) { const char *value = LuaToString(l, 2, j + 1); ++j; if (!strcmp(value, "type")) { type = UnitTypeByIdent(LuaToString(l, 2, j + 1)); } else if (!strcmp(value, "seen-type")) { seentype = UnitTypeByIdent(LuaToString(l, 2, j + 1)); } else if (!strcmp(value, "player")) { player = &Players[LuaToNumber(l, 2, j + 1)]; // During a unit's death animation (when action is "die" but the // unit still has its original type, i.e. it's still not a corpse) // the unit is already removed from map and from player's // unit list (=the unit went through LetUnitDie() which // calls RemoveUnit() and UnitLost()). Such a unit should not // be put on player's unit list! However, this state is not // easily detected from this place. It seems that it is // characterized by // unit->CurrentAction()==UnitActionDie so we have to wait // until we parsed at least Unit::Orders[]. Assert(type); unit = &UnitManager.GetSlotUnit(slot); unit->Init(*type); unit->Seen.Type = seentype; unit->Active = 0; unit->Removed = 0; Assert(UnitNumber(*unit) == slot); } else if (!strcmp(value, "current-sight-range")) { unit->CurrentSightRange = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "refs")) { unit->Refs = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "host-info")) { lua_rawgeti(l, 2, j + 1); if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 4) { LuaError(l, "incorrect argument"); } Vec2i pos; int w; int h; pos.x = LuaToNumber(l, -1, 1); pos.y = LuaToNumber(l, -1, 2); w = LuaToNumber(l, -1, 3); h = LuaToNumber(l, -1, 4); MapSight(*player, pos, w, h, unit->CurrentSightRange, MapMarkTileSight); // Detectcloak works in container if (unit->Type->DetectCloak) { MapSight(*player, pos, w, h, unit->CurrentSightRange, MapMarkTileDetectCloak); } // Radar(Jammer) not. lua_pop(l, 1); } else if (!strcmp(value, "tile")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->tilePos.x , &unit->tilePos.y, -1); lua_pop(l, 1); unit->Offset = Map.getIndex(unit->tilePos); } else if (!strcmp(value, "seen-tile")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->Seen.tilePos.x , &unit->Seen.tilePos.y, -1); lua_pop(l, 1); } else if (!strcmp(value, "stats")) { unit->Stats = &type->Stats[LuaToNumber(l, 2, j + 1)]; } else if (!strcmp(value, "pixel")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->IX , &unit->IY, -1); lua_pop(l, 1); } else if (!strcmp(value, "seen-pixel")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->Seen.IX , &unit->Seen.IY, -1); lua_pop(l, 1); } else if (!strcmp(value, "frame")) { unit->Frame = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "seen")) { unit->Seen.Frame = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "not-seen")) { unit->Seen.Frame = UnitNotSeen; --j; } else if (!strcmp(value, "direction")) { unit->Direction = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "damage-type")) { unit->DamagedType = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "attacked")) { // FIXME : unsigned long should be better handled unit->Attacked = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "auto-repair")) { unit->AutoRepair = 1; --j; } else if (!strcmp(value, "burning")) { unit->Burning = 1; --j; } else if (!strcmp(value, "destroyed")) { unit->Destroyed = 1; --j; } else if (!strcmp(value, "removed")) { unit->Removed = 1; --j; } else if (!strcmp(value, "selected")) { unit->Selected = 1; --j; } else if (!strcmp(value, "summoned")) { unit->Summoned = 1; --j; } else if (!strcmp(value, "waiting")) { unit->Waiting = 1; --j; } else if (!strcmp(value, "mine-low")) { unit->MineLow = 1; --j; } else if (!strcmp(value, "rescued-from")) { unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)]; } else if (!strcmp(value, "seen-by-player")) { const char *s = LuaToString(l, 2, j + 1); unit->Seen.ByPlayer = 0; for (int i = 0; i < PlayerMax && *s; ++i, ++s) { if (*s == '-' || *s == '_' || *s == ' ') { unit->Seen.ByPlayer &= ~(1 << i); } else { unit->Seen.ByPlayer |= (1 << i); } } } else if (!strcmp(value, "seen-destroyed")) { const char *s = LuaToString(l, 2, j + 1); unit->Seen.Destroyed = 0; for (int i = 0; i < PlayerMax && *s; ++i, ++s) { if (*s == '-' || *s == '_' || *s == ' ') { unit->Seen.Destroyed &= ~(1 << i); } else { unit->Seen.Destroyed |= (1 << i); } } } else if (!strcmp(value, "constructed")) { unit->Constructed = 1; --j; } else if (!strcmp(value, "seen-constructed")) { unit->Seen.Constructed = 1; --j; } else if (!strcmp(value, "seen-state")) { unit->Seen.State = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "active")) { unit->Active = 1; --j; } else if (!strcmp(value, "ttl")) { // FIXME : unsigned long should be better handled unit->TTL = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "threshold")) { // FIXME : unsigned long should be better handled unit->Threshold = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "group-id")) { unit->GroupId = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "last-group")) { unit->LastGroup = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "resources-held")) { unit->ResourcesHeld = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "current-resource")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->CurrentResource = CclGetResourceByName(l); lua_pop(l, 1); } else if (!strcmp(value, "pathfinder-input")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->pathFinderData->input.Load(l); lua_pop(l, 1); } else if (!strcmp(value, "pathfinder-output")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->pathFinderData->output.Load(l); lua_pop(l, 1); } else if (!strcmp(value, "wait")) { unit->Wait = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "anim-data")) { lua_rawgeti(l, 2, j + 1); CAnimations::LoadUnitAnim(l, *unit, -1); lua_pop(l, 1); } else if (!strcmp(value, "wait-anim-data")) { lua_rawgeti(l, 2, j + 1); CAnimations::LoadWaitUnitAnim(l, *unit, -1); lua_pop(l, 1); } else if (!strcmp(value, "blink")) { unit->Blink = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "moving")) { unit->Moving = 1; --j; } else if (!strcmp(value, "re-cast")) { unit->ReCast = 1; --j; } else if (!strcmp(value, "boarded")) { unit->Boarded = 1; --j; } else if (!strcmp(value, "next-worker")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->NextWorker = CclGetUnitFromRef(l); lua_pop(l, 1); } else if (!strcmp(value, "resource-workers")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->Resource.Workers = CclGetUnitFromRef(l); lua_pop(l, 1); } else if (!strcmp(value, "resource-assigned")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->Resource.Assigned = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "resource-active")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->Resource.Active = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "units-boarded-count")) { unit->BoardCount = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "units-contained")) { int subargs; int k; lua_rawgeti(l, 2, j + 1); if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } subargs = lua_rawlen(l, -1); for (k = 0; k < subargs; ++k) { lua_rawgeti(l, -1, k + 1); CUnit *u = CclGetUnitFromRef(l); lua_pop(l, 1); u->AddInContainer(*unit); } lua_pop(l, 1); } else if (!strcmp(value, "orders")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrders(l, *unit); lua_pop(l, 1); // now we know unit's action so we can assign it to a player Assert(player != NULL); unit->AssignToPlayer(*player); if (unit->CurrentAction() == UnitActionBuilt) { DebugPrint("HACK: the building is not ready yet\n"); // HACK: the building is not ready yet unit->Player->UnitTypesCount[type->Slot]--; if (unit->Active) { unit->Player->UnitTypesAiActiveCount[type->Slot]--; } } } else if (!strcmp(value, "critical-order")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrder(l, *unit , &unit->CriticalOrder); lua_pop(l, 1); } else if (!strcmp(value, "saved-order")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrder(l, *unit, &unit->SavedOrder); lua_pop(l, 1); } else if (!strcmp(value, "new-order")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrder(l, *unit, &unit->NewOrder); lua_pop(l, 1); } else if (!strcmp(value, "goal")) { unit->Goal = &UnitManager.GetSlotUnit(LuaToNumber(l, 2, j + 1)); } else if (!strcmp(value, "auto-cast")) { const char *s = LuaToString(l, 2, j + 1); Assert(SpellTypeByIdent(s)); if (!unit->AutoCastSpell) { unit->AutoCastSpell = new char[SpellTypeTable.size()]; memset(unit->AutoCastSpell, 0, SpellTypeTable.size()); } unit->AutoCastSpell[SpellTypeByIdent(s)->Slot] = 1; } else if (!strcmp(value, "spell-cooldown")) { lua_rawgeti(l, 2, j + 1); if (!lua_istable(l, -1) || lua_rawlen(l, -1) != SpellTypeTable.size()) { LuaError(l, "incorrect argument"); } if (!unit->SpellCoolDownTimers) { unit->SpellCoolDownTimers = new int[SpellTypeTable.size()]; memset(unit->SpellCoolDownTimers, 0, SpellTypeTable.size() * sizeof(int)); } for (size_t k = 0; k < SpellTypeTable.size(); ++k) { unit->SpellCoolDownTimers[k] = LuaToNumber(l, -1, k + 1); } lua_pop(l, 1); } else { const int index = UnitTypeVar.VariableNameLookup[value];// User variables if (index != -1) { // Valid index lua_rawgeti(l, 2, j + 1); DefineVariableField(l, unit->Variable + index, -1); lua_pop(l, 1); continue; } LuaError(l, "Unit: Unsupported tag: %s" _C_ value); } } // Unit may not have been assigned to a player before now. If not, // do so now. It is only assigned earlier if we have orders. // for loading of units from a MAP, and not a savegame, we won't // have orders for those units. They should appear here as if // they were just created. if (!unit->Player) { Assert(player); unit->AssignToPlayer(*player); UpdateForNewUnit(*unit, 0); } // Revealers are units that can see while removed if (unit->Removed && unit->Type->Revealer) { MapMarkUnitSight(*unit); } // Fix Colors for rescued units. if (unit->RescuedFrom) { unit->Colors = &unit->RescuedFrom->UnitColors; } return 0; }