/** ** Load the graphics for the unit-types. */ void LoadUnitTypes(void) { CUnitType *type; for (size_t i = 0; i < UnitTypes.size(); ++i) { type = UnitTypes[i]; // // Lookup icons. // type->Icon.Load(); // // Lookup missiles. // type->Missile.Missile = MissileTypeByIdent(type->Missile.Name); if (!type->Explosion.Name.empty()) { type->Explosion.Missile = MissileTypeByIdent(type->Explosion.Name); } // // Lookup corpse. // if (!type->CorpseName.empty()) { type->CorpseType = UnitTypeByIdent(type->CorpseName); } // // Load Sprite // if (!type->Sprite) { ShowLoadProgress("Unit \"%s\"", type->Name.c_str()); LoadUnitTypeSprite(type); } } }
/* virtual */ void Spell_SpawnPortal::Parse(lua_State *l, int startIndex, int endIndex) { for (int j = startIndex; j < endIndex; ++j) { lua_rawgeti(l, -1, j + 1); const char *value = LuaToString(l, -1); lua_pop(l, 1); ++j; if (!strcmp(value, "portal-type")) { lua_rawgeti(l, -1, j + 1); value = LuaToString(l, -1); lua_pop(l, 1); this->PortalType = UnitTypeByIdent(value); if (!this->PortalType) { this->PortalType = 0; DebugPrint("unit type \"%s\" not found for spawn-portal.\n" _C_ value); } } else { LuaError(l, "Unsupported spawn-portal tag: %s" _C_ value); } } // Now, checking value. if (this->PortalType == NULL) { LuaError(l, "Use a unittype for spawn-portal (with portal-type)"); } }
/* virtual */ void Spell_Polymorph::Parse(lua_State *l, int startIndex, int endIndex) { for (int j = startIndex; j < endIndex; ++j) { lua_rawgeti(l, -1, j + 1); const char *value = LuaToString(l, -1); lua_pop(l, 1); ++j; if (!strcmp(value, "new-form")) { lua_rawgeti(l, -1, j + 1); value = LuaToString(l, -1); lua_pop(l, 1); this->NewForm = UnitTypeByIdent(value); if (!this->NewForm) { this->NewForm = 0; DebugPrint("unit type \"%s\" not found for polymorph spell.\n" _C_ value); } // FIXME: temp polymorphs? hard to do. } else if (!strcmp(value, "player-neutral")) { this->PlayerNeutral = 1; --j; } else if (!strcmp(value, "player-caster")) { this->PlayerNeutral = 2; --j; } else { LuaError(l, "Unsupported polymorph tag: %s" _C_ value); } } // Now, checking value. if (this->NewForm == NULL) { LuaError(l, "Use a unittype for polymorph (with new-form)"); } }
/** ** Check if this upgrade or unit is available. ** ** @param player For this player available. ** @param target Unit or Upgrade. ** ** @return True if available, false otherwise. */ bool CheckDependByIdent(const CPlayer *player, const std::string &target) { DependRule rule; // // first have to check, if target is allowed itself // if (!strncmp(target.c_str(), "unit-", 5)) { // target string refers to unit-XXX rule.Kind.UnitType = UnitTypeByIdent(target); if (UnitIdAllowed(player, rule.Kind.UnitType->Slot) == 0) { return false; } rule.Type = DependRuleUnitType; } else if (!strncmp(target.c_str(), "upgrade-", 8)) { // target string refers to upgrade-XXX rule.Kind.Upgrade = CUpgrade::Get(target); if (UpgradeIdAllowed(player, rule.Kind.Upgrade->ID) != 'A') { return false; } rule.Type = DependRuleUpgrade; } else { DebugPrint("target `%s' should be unit-type or upgrade\n" _C_ target.c_str()); return false; } return CheckDependByRule(player, rule); }
/** ** Show Map Location ** ** @param l Lua state. */ static int CclShowMapLocation(lua_State *l) { // Put a unit on map, use its properties, except for // what is listed below LuaCheckArgs(l, 4); const char *unitname = LuaToString(l, 5); CUnitType *unitType = UnitTypeByIdent(unitname); if (!unitType) { DebugPrint("Unable to find UnitType '%s'" _C_ unitname); return 0; } CUnit *target = MakeUnit(*unitType, ThisPlayer); if (target != NULL) { target->Variable[HP_INDEX].Value = 0; target->tilePos.x = LuaToNumber(l, 1); target->tilePos.y = LuaToNumber(l, 2); target->TTL = GameCycle + LuaToNumber(l, 4); target->CurrentSightRange = LuaToNumber(l, 3); //Wyrmgus start UpdateUnitSightRange(*target); //Wyrmgus end MapMarkUnitSight(*target); } else { DebugPrint("Unable to allocate Unit"); } return 0; }
/* virtual */ void Spell_Summon::Parse(lua_State *l, int startIndex, int endIndex) { for (int j = startIndex; j < endIndex; ++j) { const char *value = LuaToString(l, -1, j + 1); ++j; if (!strcmp(value, "unit-type")) { value = LuaToString(l, -1, j + 1); this->UnitType = UnitTypeByIdent(value); if (!this->UnitType) { this->UnitType = 0; DebugPrint("unit type \"%s\" not found for summon spell.\n" _C_ value); } } else if (!strcmp(value, "time-to-live")) { this->TTL = LuaToNumber(l, -1, j + 1); } else if (!strcmp(value, "require-corpse")) { this->RequireCorpse = true; --j; } else if (!strcmp(value, "join-to-ai-force")) { this->JoinToAiForce = true; --j; } else { LuaError(l, "Unsupported summon tag: %s" _C_ value); } } // Now, checking value. if (this->UnitType == NULL) { LuaError(l, "Use a unittype for summon (with unit-type)"); } }
/** ** Checks if dependencies are met. ** ** @return true if the dependencies are met. ** ** @param l Lua state. ** Argument 1: player ** Argument 2: object which we want to check the dependencies of */ static int CclCheckDependency(lua_State *l) { LuaCheckArgs(l, 2); const char *object = LuaToString(l, 2); lua_pop(l, 1); const int plynr = TriggerGetPlayer(l); if (plynr == -1) { LuaError(l, "bad player: %i" _C_ plynr); } const CPlayer *player = &Players[plynr]; if (!strncmp(object, "unit-", 5)) { const CUnitType *unit_type = UnitTypeByIdent(object); if (!unit_type) { LuaError(l, "Invalid unit type: \"%s\"" _C_ object); } lua_pushboolean(l, CheckDependencies(unit_type, player)); } else if (!strncmp(object, "upgrade-", 8)) { const CUpgrade *upgrade = CUpgrade::Get(object); if (!upgrade) { LuaError(l, "Invalid upgrade: \"%s\"" _C_ object); } lua_pushboolean(l, CheckDependencies(upgrade, player)); } else { LuaError(l, "Invalid target of dependency check: \"%s\"" _C_ object); } return 1; }
/** ** Load the graphics for the unit-types. */ void LoadUnitTypes() { for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) { CUnitType &type = *UnitTypes[i]; // Lookup icons. type.Icon.Load(); // Lookup missiles. type.Missile.MapMissile(); type.Explosion.MapMissile(); // Lookup impacts for (int i = 0; i < ANIMATIONS_DEATHTYPES + 2; ++i) { type.Impact[i].MapMissile(); } // Lookup corpse. if (!type.CorpseName.empty()) { type.CorpseType = UnitTypeByIdent(type.CorpseName); } #ifndef DYNAMIC_LOAD // Load Sprite if (!type.Sprite) { ShowLoadProgress(_("Unit \"%s\""), type.Name.c_str()); LoadUnitTypeSprite(type); } #endif // FIXME: should i copy the animations of same graphics? } }
/** ** Check if this upgrade or unit is available. ** ** @param player For this player available. ** @param target Unit or Upgrade. ** ** @return True if available, false otherwise. */ std::string PrintDependencies(const CPlayer &player, const ButtonAction &button) { std::string rules; // // first have to check, if target is allowed itself // if (!strncmp(button.ValueStr.c_str(), "unit-", 5)) { // target string refers to unit-XXX const CUnitType *unit_type = UnitTypeByIdent(button.ValueStr); if (unit_type->Dependency) { rules = unit_type->Dependency->GetString(); } } else if (!strncmp(button.ValueStr.c_str(), "upgrade-", 8)) { // target string refers to upgrade-XXX const CUpgrade *upgrade = CUpgrade::Get(button.ValueStr); if (upgrade->Dependency) { rules = upgrade->Dependency->GetString(); } } else { DebugPrint("target '%s' should be unit-type or upgrade\n" _C_ button.ValueStr.c_str()); return rules; } if (rules.empty()) { //no dependencies found return rules; } rules.insert(0, _("Requirements:\n")); return rules; }
/* virtual */ bool COrder_Build::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { if (!strcmp(value, "building")) { ++j; lua_rawgeti(l, -1, j + 1); this->BuildingUnit = CclGetUnitFromRef(l); lua_pop(l, 1); } else if (!strcmp(value, "range")) { ++j; this->Range = LuaToNumber(l, -1, j + 1); } else if (!strcmp(value, "state")) { ++j; this->State = LuaToNumber(l, -1, j + 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 if (!strcmp(value, "type")) { ++j; this->Type = UnitTypeByIdent(LuaToString(l, -1, j + 1)); } else { return false; } return true; }
/* virtual */ bool COrder_TransformInto::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { if (!strcmp(value, "type")) { ++j; this->Type = UnitTypeByIdent(LuaToString(l, -1, j + 1)); } else { return false; } return true; }
/** ** UnitType ID by identifier. ** ** @param ident The unit-type identifier. ** @return Unit-type ID (int) or -1 if not found. */ int UnitTypeIdByIdent(const std::string &ident) { const CUnitType *type; if ((type = UnitTypeByIdent(ident))) { return type->Slot; } DebugPrint(" fix this %s\n" _C_ ident.c_str()); Assert(0); return -1; }
/* virtual */ bool COrder_UpgradeTo::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { if (!strcmp(value, "type")) { ++j; this->Type = UnitTypeByIdent(LuaToString(l, -1, j + 1)); } else if (!strcmp(value, "ticks")) { ++j; this->Ticks = LuaToNumber(l, -1, j + 1); } else { return false; } return true; }
/** ** Parse AiBuildQueue builing list ** ** @param l Lua state. ** @param ai PlayerAi pointer which should be filled with the data. */ static void CclParseBuildQueue(lua_State *l, PlayerAi *ai, int offset) { if (!lua_istable(l, offset)) { LuaError(l, "incorrect argument"); } Vec2i pos(-1, -1); const int args = lua_rawlen(l, offset); for (int k = 0; k < args; ++k) { lua_rawgeti(l, offset, k + 1); const char *value = LuaToString(l, -1); lua_pop(l, 1); ++k; if (!strcmp(value, "onpos")) { lua_rawgeti(l, offset, k + 1); pos.x = LuaToNumber(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, offset, k + 1); pos.y = LuaToNumber(l, -1); lua_pop(l, 1); } else { //lua_rawgeti(l, j + 1, k + 1); //ident = LuaToString(l, -1); //lua_pop(l, 1); //++k; lua_rawgeti(l, offset, k + 1); const int made = LuaToNumber(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, offset, k + 1); const int want = LuaToNumber(l, -1); lua_pop(l, 1); AiBuildQueue queue; queue.Type = UnitTypeByIdent(value); queue.Want = want; queue.Made = made; queue.Pos = pos; ai->UnitTypeBuilt.push_back(queue); pos.x = -1; pos.y = -1; } } }
void CUnitTypeDependency::ProcessConfigDataProperty(const std::pair<std::string, std::string> &property) { const std::string &key = property.first; std::string value = property.second; if (key == "unit_type") { value = FindAndReplaceString(value, "_", "-"); this->UnitType = UnitTypeByIdent(value); if (!this->UnitType) { fprintf(stderr, "Invalid unit type: \"%s\".\n", value.c_str()); } } else if (key == "count") { this->Count = std::stoi(value); } else { fprintf(stderr, "Invalid unit type dependency property: \"%s\".\n", key.c_str()); } }
/* virtual */ bool COrder_Train::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { if (!strcmp(value, "type")) { ++j; this->Type = UnitTypeByIdent(LuaToString(l, -1, j + 1)); //Wyrmgus start } else if (!strcmp(value, "player")) { ++j; this->Player = LuaToNumber(l, -1, j + 1); //Wyrmgus end } else if (!strcmp(value, "ticks")) { ++j; this->Ticks = LuaToNumber(l, -1, j + 1); } else { return false; } return true; }
/** ** Transform list of unit separed with coma to a true list. */ static std::vector<CUnitType *> getUnitTypeFromString(const std::string &list) { std::vector<CUnitType *> res; if (list == "*") { return UnitTypes; } size_t begin = 1; size_t end = list.find(",", begin); while (end != std::string::npos) { std::string unitName = list.substr(begin, end - begin); begin = end + 1; end = list.find(",", begin); if (!unitName.empty()) { Assert(unitName[0] != ','); res.push_back(UnitTypeByIdent(unitName.c_str())); } } return res; }
/* virtual */ void CAnimation_SpawnUnit::Action(CUnit &unit, int &/*move*/, int /*scale*/) const { Assert(unit.Anim.Anim == this); const int offX = ParseAnimInt(unit, this->offXStr.c_str()); const int offY = ParseAnimInt(unit, this->offYStr.c_str()); const int range = ParseAnimInt(unit, this->rangeStr.c_str()); const int playerId = ParseAnimInt(unit, this->playerStr.c_str()); const SpawnUnit_Flags flags = (SpawnUnit_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str())); CPlayer &player = Players[playerId]; const Vec2i pos(unit.tilePos.x + offX, unit.tilePos.y + offY); CUnitType *type = UnitTypeByIdent(this->unitTypeStr.c_str()); Assert(type); Vec2i resPos; DebugPrint("Creating a %s\n" _C_ type->Name.c_str()); FindNearestDrop(*type, pos, resPos, LookingW); if (SquareDistance(pos, resPos) <= square(range)) { CUnit *target = MakeUnit(*type, &player); if (target != NULL) { target->tilePos = resPos; target->Place(resPos); if (flags & SU_Summoned) { target->Summoned = 1; } if ((flags & SU_JoinToAIForce) && unit.Player->AiEnabled) { int force = unit.Player->Ai->Force.GetForce(unit); if (force != -1) { unit.Player->Ai->Force[force].Insert(*target); target->GroupId = unit.GroupId; CommandDefend(*target, unit, FlushCommands); } } //DropOutOnSide(*target, LookingW, NULL); } else { DebugPrint("Unable to allocate Unit"); } } }
/** ** Have unit of type. ** ** @param ident Identifier of unit-type that should be lookuped. ** ** @return How many exists, false otherwise. ** ** @note This function should not be used during run time. */ int CPlayer::HaveUnitTypeByIdent(const std::string &ident) const { return UnitTypesCount[UnitTypeByIdent(ident)->Slot]; }
/** ** Define helper for AI. ** ** @param l Lua state. ** ** @todo FIXME: the first unit could be a list see ../doc/ccl/ai.html */ static int CclDefineAiHelper(lua_State *l) { InitAiHelper(AiHelpers); const int args = lua_gettop(l); for (int j = 0; j < args; ++j) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); int k = 0; lua_rawgeti(l, j + 1, k + 1); const char *value = LuaToString(l, -1); lua_pop(l, 1); ++k; // // Type build,train,research/upgrade. // int what; if (!strcmp(value, "build")) { what = -1; } else if (!strcmp(value, "train")) { what = -1; } else if (!strcmp(value, "upgrade")) { what = -1; } else if (!strcmp(value, "research")) { what = -1; } else if (!strcmp(value, "unit-limit")) { what = -1; } else if (!strcmp(value, "unit-equiv")) { what = 5; } else if (!strcmp(value, "repair")) { what = -1; } else { LuaError(l, "unknown tag: %s" _C_ value); what = -1; } if (what == -1) { continue; } // // Get the base unit type, which could handle the action. // // FIXME: support value as list! lua_rawgeti(l, j + 1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); ++k; CUnitType *base = UnitTypeByIdent(value); if (!base) { LuaError(l, "unknown unittype: %s" _C_ value); } // // Get the unit types, which could be produced // for (; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); CUnitType *type = UnitTypeByIdent(value); if (!type) { LuaError(l, "unknown unittype: %s" _C_ value); } AiHelperInsert(AiHelpers.Equiv, base->Slot, *type); AiNewUnitTypeEquiv(base, type); } } return 0; }
/** ** Init AiHelper. ** ** @param aiHelper variable to initialise. ** ** @todo missing Equiv initialisation. */ static void InitAiHelper(AiHelper &aiHelper) { extern std::vector<ButtonAction *> UnitButtonTable; std::vector<CUnitType *> reparableUnits = getReparableUnits(); std::vector<CUnitType *> supplyUnits = getSupplyUnits(); std::vector<CUnitType *> mineUnits = getRefineryUnits(); for (std::vector<CUnitType *>::const_iterator i = supplyUnits.begin(); i != supplyUnits.end(); ++i) { AiHelperInsert(aiHelper.UnitLimit, 0, **i); } for (int i = 1; i < MaxCosts; ++i) { for (std::vector<CUnitType *>::const_iterator j = mineUnits.begin(); j != mineUnits.end(); ++j) { if ((*j)->GivesResource == i) { /* HACK : we can't mine TIME then use 0 as 1 */ AiHelperInsert(aiHelper.Refinery, i - 1, **j); } } for (std::vector<CUnitType *>::const_iterator d = UnitTypes.begin(); d != UnitTypes.end(); ++d) { CUnitType *type = *d; if (type->CanStore[i] > 0) { /* HACK : we can't store TIME then use 0 as 1 */ AiHelperInsert(aiHelper.Depots, i - 1, **d); } } } for (size_t i = 0; i != UnitButtonTable.size(); ++i) { const ButtonAction &button = *UnitButtonTable[i]; const std::vector<CUnitType *> &unitmask = getUnitTypeFromString(button.UnitMask); switch (button.Action) { case ButtonRepair : for (std::vector<CUnitType *>::const_iterator j = unitmask.begin(); j != unitmask.end(); ++j) { for (std::vector<CUnitType *>::const_iterator k = reparableUnits.begin(); k != reparableUnits.end(); ++k) { AiHelperInsert(aiHelper.Repair, (*k)->Slot, **j); } } break; case ButtonBuild: { CUnitType *buildingType = UnitTypeByIdent(button.ValueStr); for (std::vector<CUnitType *>::const_iterator j = unitmask.begin(); j != unitmask.end(); ++j) { AiHelperInsert(aiHelper.Build, buildingType->Slot, (**j)); } break; } case ButtonTrain : { CUnitType *trainingType = UnitTypeByIdent(button.ValueStr); for (std::vector<CUnitType *>::const_iterator j = unitmask.begin(); j != unitmask.end(); ++j) { AiHelperInsert(aiHelper.Train, trainingType->Slot, (**j)); } break; } case ButtonUpgradeTo : { CUnitType *upgradeToType = UnitTypeByIdent(button.ValueStr); for (std::vector<CUnitType *>::const_iterator j = unitmask.begin(); j != unitmask.end(); ++j) { AiHelperInsert(aiHelper.Upgrade, upgradeToType->Slot, **j); } break; } case ButtonResearch : { int researchId = UpgradeIdByIdent(button.ValueStr); for (std::vector<CUnitType *>::const_iterator j = unitmask.begin(); j != unitmask.end(); ++j) { AiHelperInsert(aiHelper.Research, researchId, **j); } break; } default: break; } } }
/** ** Define an AI player. ** ** @param l Lua state. */ static int CclDefineAiPlayer(lua_State *l) { const unsigned int playerIdx = LuaToNumber(l, 0 + 1); Assert(playerIdx <= PlayerMax); DebugPrint("%p %d\n" _C_(void *)Players[playerIdx].Ai _C_ Players[playerIdx].AiEnabled); // FIXME: lose this: // Assert(!Players[playerIdx].Ai && Players[playerIdx].AiEnabled); PlayerAi *ai = Players[playerIdx].Ai = new PlayerAi; ai->Player = &Players[playerIdx]; // Parse the list: (still everything could be changed!) const int args = lua_gettop(l); for (int j = 1; j < args; ++j) { const char *value = LuaToString(l, j + 1); ++j; if (!strcmp(value, "ai-type")) { const char *aiName = LuaToString(l, j + 1); CAiType *ait = GetAiTypesByName(aiName); if (ait == NULL) { lua_pushfstring(l, "ai-type not found: %s", aiName); } ai->AiType = ait; ai->Script = ait->Script; } else if (!strcmp(value, "script")) { ai->Script = LuaToString(l, j + 1); } else if (!strcmp(value, "script-debug")) { ai->ScriptDebug = LuaToBoolean(l, j + 1); } else if (!strcmp(value, "sleep-cycles")) { ai->SleepCycles = LuaToNumber(l, j + 1); } else if (!strcmp(value, "force")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); lua_rawgeti(l, j + 1, 0 + 1); const int cclforceIdx = LuaToNumber(l, -1); UNUSED(cclforceIdx); const int forceIdx = ai->Force.FindFreeForce(AiForceRoleDefault); lua_pop(l, 1); for (int k = 1; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *value = LuaToString(l, -1); lua_pop(l, 1); ++k; if (!strcmp(value, "complete")) { ai->Force[forceIdx].Completed = true; --k; } else if (!strcmp(value, "recruit")) { ai->Force[forceIdx].Completed = false; --k; } else if (!strcmp(value, "attack")) { ai->Force[forceIdx].Attacking = true; --k; } else if (!strcmp(value, "defend")) { ai->Force[forceIdx].Defending = true; --k; } else if (!strcmp(value, "role")) { lua_rawgeti(l, j + 1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); if (!strcmp(value, "attack")) { ai->Force[forceIdx].Role = AiForceRoleAttack; } else if (!strcmp(value, "defend")) { ai->Force[forceIdx].Role = AiForceRoleDefend; } else { LuaError(l, "Unsupported force tag: %s" _C_ value); } } else if (!strcmp(value, "types")) { lua_rawgeti(l, j + 1, k + 1); if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } const int subsubargs = lua_rawlen(l, -1); for (int subk = 0; subk < subsubargs; ++subk) { lua_rawgeti(l, -1, subk + 1); const int num = LuaToNumber(l, -1); lua_pop(l, 1); ++subk; lua_rawgeti(l, -1, subk + 1); const char *ident = LuaToString(l, -1); lua_pop(l, 1); AiUnitType queue; queue.Want = num; queue.Type = UnitTypeByIdent(ident); ai->Force[forceIdx].UnitTypes.push_back(queue); } lua_pop(l, 1); } else if (!strcmp(value, "units")) { lua_rawgeti(l, j + 1, k + 1); if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } const int subsubargs = lua_rawlen(l, -1); for (int subk = 0; subk < subsubargs; ++subk) { lua_rawgeti(l, -1, subk + 1); const int num = LuaToNumber(l, -1); lua_pop(l, 1); ++subk; #if 0 lua_rawgeti(l, -1, subk + 1); const char *ident = LuaToString(l, -1); UNUSED(ident); lua_pop(l, 1); #endif ai->Force[forceIdx].Units.Insert(&UnitManager.GetSlotUnit(num)); } lua_pop(l, 1); } else if (!strcmp(value, "state")) { lua_rawgeti(l, j + 1, k + 1); ai->Force[forceIdx].State = AiForceAttackingState(LuaToNumber(l, -1)); lua_pop(l, 1); } else if (!strcmp(value, "goalx")) { lua_rawgeti(l, j + 1, k + 1); ai->Force[forceIdx].GoalPos.x = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "goaly")) { lua_rawgeti(l, j + 1, k + 1); ai->Force[forceIdx].GoalPos.y = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "must-transport")) { // Keep for backward compatibility } else { LuaError(l, "Unsupported tag: %s" _C_ value); } } } else if (!strcmp(value, "reserve")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *type = LuaToString(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, j + 1, k + 1); int num = LuaToNumber(l, -1); lua_pop(l, 1); const int resId = GetResourceIdByName(l, type); ai->Reserve[resId] = num; } } else if (!strcmp(value, "used")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *type = LuaToString(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, j + 1, k + 1); const int num = LuaToNumber(l, -1); lua_pop(l, 1); const int resId = GetResourceIdByName(l, type); ai->Used[resId] = num; } } else if (!strcmp(value, "needed")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *type = LuaToString(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, j + 1, k + 1); const int num = LuaToNumber(l, -1); lua_pop(l, 1); const int resId = GetResourceIdByName(l, type); ai->Needed[resId] = num; } } else if (!strcmp(value, "collect")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *type = LuaToString(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, j + 1, k + 1); const int num = LuaToNumber(l, -1); lua_pop(l, 1); const int resId = GetResourceIdByName(l, type); ai->Collect[resId] = num; } } else if (!strcmp(value, "need-mask")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *type = LuaToString(l, -1); lua_pop(l, 1); const int resId = GetResourceIdByName(l, type); ai->NeededMask |= (1 << resId); } } else if (!strcmp(value, "need-supply")) { ai->NeedSupply = true; --j; } else if (!strcmp(value, "exploration")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { Vec2i pos; lua_rawgeti(l, j + 1, k + 1); if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 3) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, -1, 1); pos.x = LuaToNumber(l, -1); lua_pop(l, 1); lua_rawgeti(l, -1, 2); pos.y = LuaToNumber(l, -1); lua_pop(l, 1); lua_rawgeti(l, -1, 3); const int mask = LuaToNumber(l, -1); lua_pop(l, 1); lua_pop(l, 1); AiExplorationRequest queue(pos, mask); ai->FirstExplorationRequest.push_back(queue); } } else if (!strcmp(value, "last-exploration-cycle")) { ai->LastExplorationGameCycle = LuaToNumber(l, j + 1); } else if (!strcmp(value, "last-can-not-move-cycle")) { ai->LastCanNotMoveGameCycle = LuaToNumber(l, j + 1); } else if (!strcmp(value, "unit-type")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); int i = 0; if (subargs) { ai->UnitTypeRequests.resize(subargs / 2); } for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *ident = LuaToString(l, -1); lua_pop(l, 1); ++k; lua_rawgeti(l, j + 1, k + 1); const int count = LuaToNumber(l, -1); lua_pop(l, 1); ai->UnitTypeRequests[i].Type = UnitTypeByIdent(ident); ai->UnitTypeRequests[i].Count = count; ++i; } } else if (!strcmp(value, "upgrade")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *ident = LuaToString(l, -1); lua_pop(l, 1); ai->UpgradeToRequests.push_back(UnitTypeByIdent(ident)); } } else if (!strcmp(value, "research")) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); for (int k = 0; k < subargs; ++k) { lua_rawgeti(l, j + 1, k + 1); const char *ident = LuaToString(l, -1); lua_pop(l, 1); ai->ResearchRequests.push_back(CUpgrade::Get(ident)); } } else if (!strcmp(value, "building")) { CclParseBuildQueue(l, ai, j + 1); } else if (!strcmp(value, "repair-building")) { ai->LastRepairBuilding = LuaToNumber(l, j + 1); } else { LuaError(l, "Unsupported tag: %s" _C_ value); } } return 0; }
/** ** Define a new upgrade modifier. ** ** @param l List of modifiers. */ static int CclDefineModifier(lua_State *l) { const char *key; const char *value; CUpgradeModifier *um; int args; int j; args = lua_gettop(l); um = new CUpgradeModifier; memset(um->ChangeUpgrades, '?', sizeof(um->ChangeUpgrades)); memset(um->ApplyTo, '?', sizeof(um->ApplyTo)); um->Modifier.Variables = new CVariable[UnitTypeVar.NumberVariable]; um->UpgradeId = UpgradeIdByIdent(LuaToString(l, 1)); for (j = 1; j < args; ++j) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, j + 1, 1); key = LuaToString(l, -1); lua_pop(l, 1); #if 1 // To be removed. must modify lua file. if (!strcmp(key, "attack-range")) { key = "AttackRange"; } else if (!strcmp(key, "sight-range")) { key = "SightRange"; } else if (!strcmp(key, "basic-damage")) { key = "BasicDamage"; } else if (!strcmp(key, "piercing-damage")) { key = "PiercingDamage"; } else if (!strcmp(key, "armor")) { key = "Armor"; } else if (!strcmp(key, "hit-points")) { key = "HitPoints"; } #endif if (!strcmp(key, "regeneration-rate")) { lua_rawgeti(l, j + 1, 2); um->Modifier.Variables[HP_INDEX].Increase = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(key, "cost")) { int i; if (!lua_istable(l, j + 1) || luaL_getn(l, j + 1) != 2) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, j + 1, 1); value = LuaToString(l, -1); lua_pop(l, 1); for (i = 0; i < MaxCosts; ++i) { if (!strcmp(value, DefaultResourceNames[i])) { break; } } if (i == MaxCosts) { LuaError(l, "Resource not found: %s" _C_ value); } lua_rawgeti(l, j + 1, 2); um->Modifier.Costs[i] = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(key, "allow-unit")) { lua_rawgeti(l, j + 1, 2); value = LuaToString(l, -1); lua_pop(l, 1); if (!strncmp(value, "unit-", 5)) { lua_rawgeti(l, j + 1, 3); um->ChangeUnits[UnitTypeIdByIdent(value)] = LuaToNumber(l, -1); lua_pop(l, 1); } else { LuaError(l, "unit expected"); } } else if (!strcmp(key, "allow")) { lua_rawgeti(l, j + 1, 2); value = LuaToString(l, -1); lua_pop(l, 1); if (!strncmp(value, "upgrade-", 8)) { lua_rawgeti(l, j + 1, 3); um->ChangeUpgrades[UpgradeIdByIdent(value)] = LuaToNumber(l, -1); lua_pop(l, 1); } else { LuaError(l, "upgrade expected"); } } else if (!strcmp(key, "apply-to")) { lua_rawgeti(l, j + 1, 2); value = LuaToString(l, -1); lua_pop(l, 1); um->ApplyTo[UnitTypeIdByIdent(value)] = 'X'; } else if (!strcmp(key, "convert-to")) { lua_rawgeti(l, j + 1, 2); value = LuaToString(l, -1); lua_pop(l, 1); um->ConvertTo = UnitTypeByIdent(value); } else { int index; // variable index; index = GetVariableIndex(key); if (index != -1) { lua_rawgeti(l, j + 1, 2); if (lua_istable(l, -1)) { DefineVariableField(l, um->Modifier.Variables + index, -1); } else if (lua_isnumber(l, -1)) { um->Modifier.Variables[index].Enable = 1; um->Modifier.Variables[index].Value = LuaToNumber(l, -1); um->Modifier.Variables[index].Max = LuaToNumber(l, -1); } else { LuaError(l, "bad argument type for '%s'\n" _C_ key); } lua_pop(l, 1); } else { LuaError(l, "wrong tag: %s" _C_ key); } } } UpgradeModifiers[NumUpgradeModifiers++] = um; return 0; }
void HandleCommand() { char* token; int unitID; CUnit* unit; int actionID; int resourceType; int x, y; char* typeID; CUnitType* type; int destID; CUnit* dest; token = NextToken(); if (!token) return; unitID = atoi(token); unit = GetUnitByID(unitID); if (!unit) { SendResponseMessage("Unknown unit.\n", 3); return; } token = NextToken(); if (!token) return; actionID = atoi(token); switch (actionID) { case 0: // NOOP // SendResponseMessage("OK\n", 3); break; case 1: // STOP SendCommandStopUnit(unit); // SendResponseMessage("OK\n", 3); break; case 2: // MoveTo <X> <Y> token = NextToken(); if (token == NULL) { SendResponseMessage("Bad arguments to Move Action.\n", 3); return; } x = atoi(token); token = NextToken(); if (token == NULL) { SendResponseMessage("Bad arguments to Move Action.\n", 3); return; } y = atoi(token); SendCommandMove(unit, x, y, 1); // SendResponseMessage("OK\n", 3); break; case 3: // Build <Type> <X> <Y> token = NextToken(); if (token == NULL) { SendResponseMessage("Bad arguments to Build Action.\n", 3); return; } typeID = token; type = UnitTypeByIdent(typeID); if (type == NULL) { SendResponseMessage("Unknown type to build.\n", 3); return; } // If it's a building, train the unit. if (unit->Type->Building) SendCommandTrainUnit(unit, type, 1); else // otherwise, build a building. { token = NextToken(); if (token == NULL) { SendResponseMessage("Bad arguments to Build Action.\n", 3); return; } x = atoi(token); token = NextToken(); if (token == NULL) { SendResponseMessage("Bad arguments to Build Action.\n", 3); return; } y = atoi(token); SendCommandBuildBuilding(unit, x, y, type, 1); } SendResponseMessage("OK\n", 3); break; case 4: // Attack <UnitID> token = NextToken(); if (!token) return; destID = atoi(token); dest = GetUnitByID(destID); if (!dest) { SendResponseMessage("Unknown unit to attack.\n", 3); return; } SendCommandAttack(unit, 0, 0, dest, 1); SendResponseMessage("OK\n", 3); break; case 5: // Repair <UnitID> token = NextToken(); if (!token) return; destID = atoi(token); dest = GetUnitByID(destID); if (!dest) { SendResponseMessage("Unknown unit to repair.\n", 3); return; } SendCommandRepair(unit, 0, 0, dest, 1); SendResponseMessage("OK\n", 3); break; case 6: // Harvest <ResourceType> token = NextToken(); if (!token) return; resourceType = atoi(token); // GOLD = 1, WOOD = 2 FindAndGatherResource(unit, resourceType); break; case 7: // Return resource ReturnResource(unit); break; case 8: // Harvest unit (gold/oil) <DestUnit> token = NextToken(); if (!token) { SendResponseMessage("Invalid harvest argument.\n", 3); return; } destID = atoi(token); dest = GetUnitByID(destID); if (dest == NoUnitP) { SendResponseMessage("Invalid resource unit ID.\n", 3); return; } SendCommandResource(unit, dest, 1); SendResponseMessage("OK\n", 3); break; case 9: // Harvest terrain (wood) <X> <Y> token = NextToken(); if (!token) { SendResponseMessage("Invalid harvest argument.\n", 3); return; } x = atoi(token); token = NextToken(); if (!token) { SendResponseMessage("Invalid harvest argument.\n", 3); return; } y = atoi(token); SendCommandResourceLoc(unit, x, y, 1); SendResponseMessage("OK\n", 3); break; case 10: // Harvest location <ResourceType> <X> <Y> token = NextToken(); if (!token) { SendResponseMessage("Invalid harvest argument.\n", 3); return; } resourceType = atoi(token); // GOLD = 1, WOOD = 2 token = NextToken(); if (!token) { SendResponseMessage("Invalid harvest argument.\n", 3); return; } x = atoi(token); token = NextToken(); if (!token) { SendResponseMessage("Invalid harvest argument.\n", 3); return; } y = atoi(token); HarvestResAtLoc(resourceType, x, y); break; default: SendResponseMessage("Unknown command.\n", 3); return; } }
/** ** Add a new dependency. If already exits append to and rule. ** ** @param target Target of the dependency. ** @param required Requirement of the dependency. ** @param count Amount of the required needed. ** @param or_flag Start of or rule. */ static void AddDependency(const std::string &target, const std::string required, int count, int or_flag) { DependRule rule; DependRule *node; DependRule *temp; int hash; // // Setup structure. // if (!strncmp(target.c_str(), "unit-", 5)) { // target string refers to unit-xxx rule.Type = DependRuleUnitType; rule.Kind.UnitType = UnitTypeByIdent(target); } else if (!strncmp(target.c_str(), "upgrade-", 8)) { // target string refers to upgrade-XXX rule.Type = DependRuleUpgrade; rule.Kind.Upgrade = CUpgrade::Get(target); } else { DebugPrint("dependency target `%s' should be unit-type or upgrade\n" _C_ target.c_str()); return; } hash = (int)((intptr_t)rule.Kind.UnitType % (sizeof(DependHash) / sizeof(*DependHash))); // // Find correct hash slot. // if ((node = DependHash[hash])) { // find correct entry while (node->Type != rule.Type || node->Kind.Upgrade != rule.Kind.Upgrade) { if (!node->Next) { // end of list temp = new DependRule; temp->Next = NULL; temp->Rule = NULL; temp->Type = rule.Type; temp->Kind = rule.Kind; node->Next = temp; node = temp; break; } node = node->Next; } } else { // create new slow node = new DependRule; node->Next = NULL; node->Rule = NULL; node->Type = rule.Type; node->Kind = rule.Kind; DependHash[hash] = node; } // // Adjust count. // if (count < 0 || count > 255) { DebugPrint("wrong count `%d' range 0 .. 255\n" _C_ count); count = 255; } temp = new DependRule; temp->Rule = NULL; temp->Next = NULL; temp->Count = count; // // Setup structure. // if (!strncmp(required.c_str(), "unit-", 5)) { // required string refers to unit-xxx temp->Type = DependRuleUnitType; temp->Kind.UnitType = UnitTypeByIdent(required); } else if (!strncmp(required.c_str(), "upgrade-", 8)) { // required string refers to upgrade-XXX temp->Type = DependRuleUpgrade; temp->Kind.Upgrade = CUpgrade::Get(required); } else { DebugPrint("dependency required `%s' should be unit-type or upgrade\n" _C_ required.c_str()); delete temp; return; } if (or_flag) { // move rule to temp->next temp->Next = node->Rule; // insert rule node->Rule = temp; } else { // move rule to temp->rule temp->Rule = node->Rule; // insert rule // also Link temp to old "or" list if (node->Rule) { temp->Next = node->Rule->Next; } node->Rule = temp; } #ifdef neverDEBUG printf("New rules are :"); node = node->Rule; while (node) { temp = node; while (temp) { printf("temp->Kind.UnitType=%p ", temp->Kind.UnitType); temp = temp->Rule; } node = node->Next; printf("\n or ... "); } printf("\n"); #endif }
/** ** Have unit of type. ** ** @param player Pointer to owning player. ** @param ident Identifier of unit-type that should be lookuped. ** @return How many exists, false otherwise. ** ** @note This function should not be used during run time. */ global int HaveUnitTypeByIdent(const Player* player,const char* ident) { return player->UnitTypesCount[UnitTypeByIdent(ident)->Type]; }
static int CclDefinePredependency(lua_State *l) { const int args = lua_gettop(l); const char *target = LuaToString(l, 1); std::vector<const CDependency *> and_dependencies; // All or rules. bool or_flag = false; for (int j = 1; j < args; ++j) { if (!lua_istable(l, j + 1)) { LuaError(l, "incorrect argument"); } const int subargs = lua_rawlen(l, j + 1); std::vector<const CDependency *> dependencies; for (int k = 0; k < subargs; ++k) { const char *required = LuaToString(l, j + 1, k + 1); int count = 1; if (k + 1 < subargs) { lua_rawgeti(l, j + 1, k + 2); if (lua_isnumber(l, -1)) { count = LuaToNumber(l, -1); ++k; } lua_pop(l, 1); } CDependency *dependency = nullptr; if (!strncmp(required, "unit-", 5)) { const CUnitType *unit_type = UnitTypeByIdent(required); if (!unit_type) { LuaError(l, "Invalid unit type: \"%s\"" _C_ required); } dependency = new CUnitTypeDependency(unit_type, count > 0 ? count : 1); } else if (!strncmp(required, "upgrade-", 8)) { const CUpgrade *upgrade = CUpgrade::Get(required); if (!upgrade) { LuaError(l, "Invalid upgrade: \"%s\"" _C_ required); } dependency = new CUpgradeDependency(upgrade); } else { LuaError(l, "Invalid required type for dependency: \"%s\"" _C_ required); } if (count == 0) { dependency = new CNotDependency(dependency); } dependencies.push_back(dependency); } if (j + 1 < args) { ++j; const char *value = LuaToString(l, j + 1); if (strcmp(value, "or")) { LuaError(l, "not or symbol: %s" _C_ value); return 0; } or_flag = true; } and_dependencies.push_back(new CAndDependency(dependencies)); dependencies.clear(); } CDependency *dependency = nullptr; if (or_flag) { dependency = new COrDependency(and_dependencies); } else { dependency = new CAndDependency(and_dependencies); } if (!strncmp(target, "unit-", 5)) { CUnitType *unit_type = UnitTypeByIdent(target); if (!unit_type) { LuaError(l, "Invalid unit type: \"%s\"" _C_ target); } unit_type->Predependency = dependency; } else if (!strncmp(target, "upgrade-", 8)) { CUpgrade *upgrade = CUpgrade::Get(target); if (!upgrade) { LuaError(l, "Invalid upgrade: \"%s\"" _C_ target); } upgrade->Predependency = dependency; } else { LuaError(l, "Invalid dependency target: \"%s\"" _C_ target); } return 0; }
/** ** Gets the player data. ** ** @param player Player number. ** @param prop Player's property. ** @param arg Additional argument (for resource and unit). ** ** @return Returning value (only integer). */ int GetPlayerData(const int player, const char *prop, const char *arg) { if (!strcmp(prop, "RaceName")) { return Players[player].Race; } else if (!strcmp(prop, "Resources")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } return Players[player].Resources[resId] + Players[player].StoredResources[resId]; } else if (!strcmp(prop, "StoredResources")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } return Players[player].StoredResources[resId]; } else if (!strcmp(prop, "MaxResources")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } return Players[player].MaxResources[resId]; } else if (!strcmp(prop, "Incomes")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } return Players[player].Incomes[resId]; } else if (!strcmp(prop, "UnitTypesCount")) { const std::string unit(arg); CUnitType *type = UnitTypeByIdent(unit); Assert(type); return Players[player].UnitTypesCount[type->Slot]; } else if (!strcmp(prop, "AiEnabled")) { return Players[player].AiEnabled; } else if (!strcmp(prop, "TotalNumUnits")) { return Players[player].GetUnitCount(); } else if (!strcmp(prop, "NumBuildings")) { return Players[player].NumBuildings; } else if (!strcmp(prop, "Supply")) { return Players[player].Supply; } else if (!strcmp(prop, "Demand")) { return Players[player].Demand; } else if (!strcmp(prop, "UnitLimit")) { return Players[player].UnitLimit; } else if (!strcmp(prop, "BuildingLimit")) { return Players[player].BuildingLimit; } else if (!strcmp(prop, "TotalUnitLimit")) { return Players[player].TotalUnitLimit; } else if (!strcmp(prop, "Score")) { return Players[player].Score; } else if (!strcmp(prop, "TotalUnits")) { return Players[player].TotalUnits; } else if (!strcmp(prop, "TotalBuildings")) { return Players[player].TotalBuildings; } else if (!strcmp(prop, "TotalResources")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } return Players[player].TotalResources[resId]; } else if (!strcmp(prop, "TotalRazings")) { return Players[player].TotalRazings; } else if (!strcmp(prop, "TotalKills")) { return Players[player].TotalKills; } else { fprintf(stderr, "Invalid field: %s" _C_ prop); Exit(1); } return 0; }
/** ** 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; }
/** ** Do next replay */ static void DoNextReplay() { Assert(ReplayStep != 0); NextLogCycle = ReplayStep->GameCycle; if (NextLogCycle != GameCycle) { return; } const int unitSlot = ReplayStep->UnitNumber; const char *action = ReplayStep->Action.c_str(); const int flags = ReplayStep->Flush; const Vec2i pos(ReplayStep->PosX, ReplayStep->PosY); const int arg1 = ReplayStep->PosX; const int arg2 = ReplayStep->PosY; CUnit *unit = unitSlot != -1 ? &UnitManager.GetSlotUnit(unitSlot) : NULL; CUnit *dunit = (ReplayStep->DestUnitNumber != -1 ? &UnitManager.GetSlotUnit(ReplayStep->DestUnitNumber) : NULL); const char *val = ReplayStep->Value.c_str(); const int num = ReplayStep->Num; Assert(unitSlot == -1 || ReplayStep->UnitIdent == unit->Type->Ident); if (SyncRandSeed != ReplayStep->SyncRandSeed) { #ifdef DEBUG if (!ReplayStep->SyncRandSeed) { // Replay without the 'sync info ThisPlayer->Notify("%s", _("No sync info for this replay !")); } else { ThisPlayer->Notify(_("Replay got out of sync (%lu) !"), GameCycle); DebugPrint("OUT OF SYNC %u != %u\n" _C_ SyncRandSeed _C_ ReplayStep->SyncRandSeed); DebugPrint("OUT OF SYNC GameCycle %lu \n" _C_ GameCycle); Assert(0); // ReplayStep = 0; // NextLogCycle = ~0UL; // return; } #else ThisPlayer->Notify("%s", _("Replay got out of sync !")); ReplayStep = 0; NextLogCycle = ~0UL; return; #endif } if (!strcmp(action, "stop")) { SendCommandStopUnit(*unit); } else if (!strcmp(action, "stand-ground")) { SendCommandStandGround(*unit, flags); } else if (!strcmp(action, "defend")) { SendCommandDefend(*unit, *dunit, flags); } else if (!strcmp(action, "follow")) { SendCommandFollow(*unit, *dunit, flags); } else if (!strcmp(action, "move")) { SendCommandMove(*unit, pos, flags); //Wyrmgus start } else if (!strcmp(action, "pick-up")) { SendCommandPickUp(*unit, *dunit, flags); //Wyrmgus end } else if (!strcmp(action, "repair")) { SendCommandRepair(*unit, pos, dunit, flags); } else if (!strcmp(action, "auto-repair")) { SendCommandAutoRepair(*unit, arg1); } else if (!strcmp(action, "attack")) { SendCommandAttack(*unit, pos, dunit, flags); } else if (!strcmp(action, "attack-ground")) { SendCommandAttackGround(*unit, pos, flags); //Wyrmgus start } else if (!strcmp(action, "use")) { SendCommandUse(*unit, *dunit, flags); } else if (!strcmp(action, "trade")) { SendCommandTrade(*unit, *dunit, flags); //Wyrmgus end } else if (!strcmp(action, "patrol")) { SendCommandPatrol(*unit, pos, flags); } else if (!strcmp(action, "board")) { SendCommandBoard(*unit, *dunit, flags); } else if (!strcmp(action, "unload")) { SendCommandUnload(*unit, pos, dunit, flags); } else if (!strcmp(action, "build")) { SendCommandBuildBuilding(*unit, pos, *UnitTypeByIdent(val), flags); } else if (!strcmp(action, "dismiss")) { SendCommandDismiss(*unit); } else if (!strcmp(action, "resource-loc")) { SendCommandResourceLoc(*unit, pos, flags); } else if (!strcmp(action, "resource")) { SendCommandResource(*unit, *dunit, flags); } else if (!strcmp(action, "return")) { SendCommandReturnGoods(*unit, dunit, flags); } else if (!strcmp(action, "train")) { //Wyrmgus start // SendCommandTrainUnit(*unit, *UnitTypeByIdent(val), flags); SendCommandTrainUnit(*unit, *UnitTypeByIdent(val), num, flags); //Wyrmgus end } else if (!strcmp(action, "cancel-train")) { SendCommandCancelTraining(*unit, num, (val && *val) ? UnitTypeByIdent(val) : NULL); } else if (!strcmp(action, "upgrade-to")) { SendCommandUpgradeTo(*unit, *UnitTypeByIdent(val), flags); } else if (!strcmp(action, "cancel-upgrade-to")) { SendCommandCancelUpgradeTo(*unit); //Wyrmgus start } else if (!strcmp(action, "transform-into")) { SendCommandTransformInto(*unit, *UnitTypeByIdent(val), flags); //Wyrmgus end } else if (!strcmp(action, "research")) { //Wyrmgus start // SendCommandResearch(*unit, *CUpgrade::Get(val), flags); SendCommandResearch(*unit, *CUpgrade::Get(val), num, flags); //Wyrmgus end } else if (!strcmp(action, "cancel-research")) { SendCommandCancelResearch(*unit); //Wyrmgus start } else if (!strcmp(action, "learn-ability")) { SendCommandLearnAbility(*unit, *CUpgrade::Get(val)); //Wyrmgus end } else if (!strcmp(action, "spell-cast")) { SendCommandSpellCast(*unit, pos, dunit, num, flags); } else if (!strcmp(action, "auto-spell-cast")) { SendCommandAutoSpellCast(*unit, num, arg1); //Wyrmgus start } else if (!strcmp(action, "rally-point")) { SendCommandRallyPoint(*unit, pos); } else if (!strcmp(action, "quest")) { SendCommandQuest(*unit, GetQuest(val)); } else if (!strcmp(action, "buy")) { SendCommandBuy(*unit, dunit, num); } else if (!strcmp(action, "produce-resource")) { SendCommandProduceResource(*unit, num); } else if (!strcmp(action, "sell-resource")) { SendCommandSellResource(*unit, arg1, num); } else if (!strcmp(action, "buy-resource")) { SendCommandBuyResource(*unit, arg1, num); //Wyrmgus end } else if (!strcmp(action, "diplomacy")) { int state; if (!strcmp(val, "neutral")) { state = DiplomacyNeutral; } else if (!strcmp(val, "allied")) { state = DiplomacyAllied; } else if (!strcmp(val, "enemy")) { state = DiplomacyEnemy; //Wyrmgus start } else if (!strcmp(val, "overlord")) { state = DiplomacyOverlord; } else if (!strcmp(val, "vassal")) { state = DiplomacyVassal; //Wyrmgus end } else if (!strcmp(val, "crazy")) { state = DiplomacyCrazy; } else { DebugPrint("Invalid diplomacy command: %s" _C_ val); state = -1; } SendCommandDiplomacy(arg1, state, arg2); } else if (!strcmp(action, "shared-vision")) { bool state; state = atoi(val) ? true : false; SendCommandSharedVision(arg1, state, arg2); } else if (!strcmp(action, "input")) { if (val[0] == '-') { CclCommand(val + 1, false); } else { HandleCheats(val); } } else if (!strcmp(action, "chat")) { SetMessage("%s", val); PlayGameSound(GameSounds.ChatMessage.Sound, MaxSampleVolume); } else if (!strcmp(action, "quit")) { CommandQuit(arg1); } else { DebugPrint("Invalid action: %s" _C_ action); } ReplayStep = ReplayStep->Next; NextLogCycle = ReplayStep ? (unsigned)ReplayStep->GameCycle : ~0UL; }