diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index a812eca12..89a2dd426 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -477,7 +477,7 @@ void COrder_Attack::AttackTarget(CUnit &unit) return; } // Save current command to come back. - COrder *savedOrder = this->Clone(); + COrder *savedOrder = COrder::NewActionAttack(unit, this->goalPos); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp index b089eda5c..cab047d4f 100644 --- a/src/action/action_upgradeto.cpp +++ b/src/action/action_upgradeto.cpp @@ -116,7 +116,7 @@ static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype) for (int i = 0; i < MaxCosts; ++i) { if (player.MaxResources[i] != -1) { player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i]; - player.SetResource(i, player.StoredResources[i], true); + player.SetResource(i, player.StoredResources[i], STORE_BUILDING); } } diff --git a/src/ai/ai_magic.cpp b/src/ai/ai_magic.cpp index d3e40c3d4..4b906fcde 100644 --- a/src/ai/ai_magic.cpp +++ b/src/ai/ai_magic.cpp @@ -37,6 +37,7 @@ #include "unittype.h" #include "unit.h" #include "spells.h" +#include "actions.h" #include "ai_local.h" /*---------------------------------------------------------------------------- @@ -55,8 +56,8 @@ void AiCheckMagic() for (int i = 0; i < n; ++i) { CUnit &unit = player.GetUnit(i); - // Check only magic units - if (unit.Type->CanCastSpell) { + // Check only idle magic units + if (unit.Type->CanCastSpell && unit.CurrentAction() != UnitActionSpellCast) { for (unsigned int j = 0; j < SpellTypeTable.size(); ++j) { // Check if we can cast this spell. SpellIsAvailable checks for upgrades. if (unit.Type->CanCastSpell[j] && SpellIsAvailable(player, j) diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp index cad4a9242..7fb1f3ebe 100644 --- a/src/animation/animation.cpp +++ b/src/animation/animation.cpp @@ -39,6 +39,8 @@ #include "stratagus.h" +#include "action/action_spellcast.h" + #include "animation.h" #include "animation/animation_attack.h" @@ -66,6 +68,7 @@ #include "iolib.h" #include "player.h" #include "script.h" +#include "spells.h" #include "unit.h" #include "unittype.h" @@ -178,6 +181,22 @@ int ParseAnimInt(const CUnit *unit, const char *parseint) return goal->Variable[index].Value * 100 / goal->Variable[index].Max; } return 0; + } else if ((s[0] == 'b') && unit != NULL) { //unit bool flag detected + const int index = UnitTypeVar.BoolFlagNameLookup[cur];// User bool flags + if (index == -1) { + fprintf(stderr, "Bad bool-flag name '%s'\n", cur); + Exit(1); + return 0; + } + return goal->Type->BoolFlag[index].value; + } else if ((s[0] == 's') && unit != NULL) { //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] == 'p' && unit != NULL) { //player variable detected char *next = strchr(cur, '.'); if (next == NULL) { diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp index 013659236..dd665deb8 100644 --- a/src/animation/animation_setplayervar.cpp +++ b/src/animation/animation_setplayervar.cpp @@ -138,14 +138,14 @@ static void SetPlayerData(int player, const char *prop, const char *arg, int val fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } - Players[player].SetResource(resId, value); + Players[player].SetResource(resId, value, STORE_BOTH); } else if (!strcmp(prop, "StoredResources")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } - Players[player].SetResource(resId, value, true); + Players[player].SetResource(resId, value, STORE_BUILDING); } else if (!strcmp(prop, "UnitLimit")) { Players[player].UnitLimit = value; } else if (!strcmp(prop, "BuildingLimit")) { diff --git a/src/include/missile.h b/src/include/missile.h index 3a5df6216..edbede9de 100644 --- a/src/include/missile.h +++ b/src/include/missile.h @@ -360,6 +360,9 @@ public: int DrawLevel; /// Level to draw missile at int SpriteFrames; /// number of sprite frames in graphic int NumDirections; /// number of directions missile can face + int ChangeVariable; /// variable to change + int ChangeAmount; /// how many to change + bool ChangeMax; /// modify the max, if value will exceed it /// @todo FiredSound defined but not used! SoundConfig FiredSound; /// fired sound diff --git a/src/include/player.h b/src/include/player.h index a6eb25767..3159ff1ed 100644 --- a/src/include/player.h +++ b/src/include/player.h @@ -45,6 +45,14 @@ #endif #include "vec2i.h" +/*---------------------------------------------------------------------------- +-- Definitons +----------------------------------------------------------------------------*/ + +#define STORE_OVERALL 0 +#define STORE_BUILDING 1 +#define STORE_BOTH 2 + /*---------------------------------------------------------------------------- -- Declarations ----------------------------------------------------------------------------*/ @@ -135,7 +143,7 @@ public: /// Adds/subtracts some resources to/from the player store void ChangeResource(int resource, int value, bool store = false); /// Set a resource of the player - void SetResource(int resource, int value, bool store = false); + void SetResource(int resource, int value, int type = STORE_OVERALL); /// Check, if there enough resources for action. bool CheckResource(int resource, int value); diff --git a/src/include/unit.h b/src/include/unit.h index 3b574a4cb..48b4a8e52 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -339,6 +339,10 @@ #include "player.h" #endif +#ifndef __MISSILE_H__ +#include "missile.h" +#endif + #include "vec2i.h" /*---------------------------------------------------------------------------- @@ -676,6 +680,10 @@ unsigned ByPlayer : PlayerMax; /// Track unit seen by player if (IsInvisibile(player)) { return false; } + // Don't attack revealers + if (this->Type->Revealer) { + return false; + } if ((player.Type == PlayerComputer && !this->Type->PermanentCloak) || IsVisible(player) || IsVisibleOnRadar(player)) { return IsAliveOnMap(); @@ -960,7 +968,7 @@ extern void DestroyAllInside(CUnit &source); /// Calculate some value to measure the unit's priority for AI extern int ThreatCalculate(const CUnit &unit, const CUnit &dest); /// Hit unit with damage, if destroyed give attacker the points -extern void HitUnit(CUnit *attacker, CUnit &target, int damage); +extern void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile = NULL); /// Calculate the distance from current view point to coordinate extern int ViewPointDistance(const Vec2i &pos); diff --git a/src/missile/missile.cpp b/src/missile/missile.cpp index 63d2d1e26..945866224 100644 --- a/src/missile/missile.cpp +++ b/src/missile/missile.cpp @@ -682,7 +682,7 @@ static void MissileHitsGoal(const Missile &missile, CUnit &goal, int splash) } else { Assert(missile.SourceUnit != NULL); HitUnit(missile.SourceUnit, goal, - CalculateDamage(*missile.SourceUnit, goal) / splash); + CalculateDamage(*missile.SourceUnit, goal) / splash, &missile); } } } @@ -1091,8 +1091,8 @@ void InitMissileTypes() ** Constructor. */ MissileType::MissileType(const std::string &ident) : - Ident(ident), Transparency(0), - DrawLevel(0), SpriteFrames(0), NumDirections(0), + Ident(ident), Transparency(0), DrawLevel(0), + SpriteFrames(0), NumDirections(0), ChangeVariable(-1), ChangeAmount(0), ChangeMax(false), CorrectSphashDamage(false), Flip(false), CanHitOwner(false), FriendlyFire(false), AlwaysFire(false), Class(), NumBounces(0), StartDelay(0), Sleep(0), Speed(0), Range(0), SplashFactor(0), ImpactParticle(NULL), G(NULL) diff --git a/src/missile/script_missile.cpp b/src/missile/script_missile.cpp index 7f7a7602a..fd0e5b55e 100644 --- a/src/missile/script_missile.cpp +++ b/src/missile/script_missile.cpp @@ -116,6 +116,18 @@ void MissileType::Load(lua_State *l) this->FiredSound.Name = LuaToString(l, -1); } else if (!strcmp(value, "ImpactSound")) { this->ImpactSound.Name = LuaToString(l, -1); + } else if (!strcmp(value, "ChangeVariable")) { + const int index = UnitTypeVar.VariableNameLookup[LuaToString(l, -1)];// User variables + if (index == -1) { + fprintf(stderr, "Bad variable name '%s'\n", LuaToString(l, -1)); + Exit(1); + return; + } + this->ChangeVariable = index; + } else if (!strcmp(value, "ChangeAmount")) { + this->ChangeAmount = LuaToNumber(l, -1); + } else if (!strcmp(value, "ChangeMax")) { + this->ChangeMax = LuaToBoolean(l, -1); } else if (!strcmp(value, "Class")) { const char *className = LuaToString(l, -1); unsigned int i = 0; diff --git a/src/stratagus/player.cpp b/src/stratagus/player.cpp index 7523e6131..abf36e3d9 100644 --- a/src/stratagus/player.cpp +++ b/src/stratagus/player.cpp @@ -812,18 +812,18 @@ int CPlayer::GetUnitCount() const ** Gets the player resource. ** ** @param resource Resource to get. -** @param store Resource type to get +** @param type Storing type ** -** @note Resource types: 0 - overall store, 1 - store buildings, 2 - both +** @note Storing types: 0 - overall store, 1 - store buildings, 2 - both */ int CPlayer::GetResource(int resource, int type) { switch (type) { - case 0: + case STORE_OVERALL: return this->Resources[resource]; - case 1: + case STORE_BUILDING: return this->StoredResources[resource]; - case 2: + case STORE_BOTH: return this->Resources[resource] + this->StoredResources[resource]; default: DebugPrint("Wrong resource type\n"); @@ -844,6 +844,9 @@ void CPlayer::ChangeResource(int resource, int value, bool store) int fromStore = std::min(this->StoredResources[resource], abs(value)); this->StoredResources[resource] -= fromStore; this->Resources[resource] -= abs(value) - fromStore; + if (this->Resources[resource] < 0) { + this->Resources[resource] = 0; + } } else { if (store && this->MaxResources[resource] != -1) { this->StoredResources[resource] += std::min(value, this->MaxResources[resource] - this->StoredResources[resource]); @@ -858,13 +861,21 @@ void CPlayer::ChangeResource(int resource, int value, bool store) ** ** @param resource Resource to change. ** @param value How many of this resource. -** @param store If true, sets the building store resources, else the overall resources. +** @param type Resource types: 0 - overall store, 1 - store buildings, 2 - both */ -void CPlayer::SetResource(int resource, int value, bool store) +void CPlayer::SetResource(int resource, int value, int type) { - if (store && this->MaxResources[resource] != -1) { + if (type == STORE_BOTH) { + if (this->MaxResources[resource] != -1) { + const int toStore = std::min(0, value - this->Resources[resource]); + this->StoredResources[resource] = std::min(toStore, this->MaxResources[resource]); + this->Resources[resource] = std::max(0, value - toStore); + } else { + this->Resources[resource] = value; + } + } else if (type == STORE_BUILDING && this->MaxResources[resource] != -1) { this->StoredResources[resource] = std::min(value, this->MaxResources[resource]); - } else { + } else if (type == STORE_OVERALL) { this->Resources[resource] = value; } } diff --git a/src/stratagus/script_player.cpp b/src/stratagus/script_player.cpp index 2b8b89a71..839c1e4f2 100644 --- a/src/stratagus/script_player.cpp +++ b/src/stratagus/script_player.cpp @@ -840,7 +840,7 @@ static int CclSetPlayerData(lua_State *l) const std::string res = LuaToString(l, 3); const int resId = GetResourceIdByName(l, res.c_str()); - p->SetResource(resId, LuaToNumber(l, 4), true); + p->SetResource(resId, LuaToNumber(l, 4), STORE_BUILDING); // } else if (!strcmp(data, "UnitTypesCount")) { // } else if (!strcmp(data, "AiEnabled")) { // } else if (!strcmp(data, "TotalNumUnits")) { diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp index c8eea988f..cb3099b62 100644 --- a/src/unit/script_unittype.cpp +++ b/src/unit/script_unittype.cpp @@ -1179,16 +1179,11 @@ static int CclDefineUnitType(lua_State *l) */ static int CclDefineUnitStats(lua_State *l) { - const int args = lua_gettop(l); - int j = 0; - - CUnitType *type = UnitTypeByIdent(LuaToString(l, j + 1)); + CUnitType *type = UnitTypeByIdent(LuaToString(l, 1)); + const int playerId = LuaToNumber(l, 2); + Assert(type); - ++j; - - int playerId = LuaToNumber(l, j + 1); Assert(playerId < PlayerMax); - ++j; CUnitStats *stats = &type->Stats[playerId]; if (!stats->Variables) { @@ -1196,51 +1191,61 @@ static int CclDefineUnitStats(lua_State *l) } // Parse the list: (still everything could be changed!) - for (; j < args; ++j) { - const char *value = LuaToString(l, j + 1); + const int args = lua_rawlen(l, 3); + for (int j = 0; j < args; ++j) { + lua_rawgeti(l, 3, j + 1); + const char *value = LuaToString(l, -1); + lua_pop(l, 1); ++j; if (!strcmp(value, "costs")) { - if (!lua_istable(l, j + 1)) { + lua_rawgeti(l, 3, j + 1); + if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } - const int subargs = lua_rawlen(l, j + 1); + const int subargs = lua_rawlen(l, -1); for (int k = 0; k < subargs; ++k) { - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, 3, j + 1); + lua_rawgeti(l, -1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); ++k; const int resId = GetResourceIdByName(l, value); - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, -1, k + 1); stats->Costs[resId] = LuaToNumber(l, -1); lua_pop(l, 1); + lua_pop(l, 1); } } else if (!strcmp(value, "storing")) { - if (!lua_istable(l, j + 1)) { + lua_rawgeti(l, 3, j + 1); + if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } - const int subargs = lua_rawlen(l, j + 1); + const int subargs = lua_rawlen(l, -1); for (int k = 0; k < subargs; ++k) { - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, 3, j + 1); + lua_rawgeti(l, -1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); ++k; const int resId = GetResourceIdByName(l, value); - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, -1, k + 1); stats->Storing[resId] = LuaToNumber(l, -1); lua_pop(l, 1); + lua_pop(l, 1); } } else { int i = UnitTypeVar.VariableNameLookup[value];// User variables if (i != -1) { // valid index - if (lua_istable(l, j + 1)) { - DefineVariableField(l, stats->Variables + i, j + 1); + lua_rawgeti(l, 3, j + 1); + if (lua_istable(l, -1)) { + DefineVariableField(l, stats->Variables + i, -1); } else if (lua_isnumber(l, -1)) { stats->Variables[i].Enable = 1; - stats->Variables[i].Value = LuaToNumber(l, j + 1); - stats->Variables[i].Max = LuaToNumber(l, j + 1); + stats->Variables[i].Value = LuaToNumber(l, -1); + stats->Variables[i].Max = LuaToNumber(l, -1); } else { // Error LuaError(l, "incorrect argument for the variable in unittype"); } diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 02be6fb1e..c916e79cb 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -959,7 +959,7 @@ void UnitLost(CUnit &unit) const int newMaxValue = player.MaxResources[i] - type.Stats[player.Index].Storing[i]; player.MaxResources[i] = std::max(0, newMaxValue); - player.SetResource(i, player.StoredResources[i], true); + player.SetResource(i, player.StoredResources[i], STORE_BUILDING); } } // Handle income improvements, look if a player loses a building @@ -2695,8 +2695,9 @@ int ThreatCalculate(const CUnit &unit, const CUnit &dest) ** @param attacker Unit that attacks. ** @param target Unit that is hit. ** @param damage How many damage to take. +** @param missile Which missile took the damage. */ -void HitUnit(CUnit *attacker, CUnit &target, int damage) +void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile) { // Can now happen by splash damage // Multiple places send x/y as damage, which may be zero @@ -2836,6 +2837,16 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage) type->OnHit->run(); } + // Increase variables + if (missile && missile->Type->ChangeVariable != -1) { + const int var = missile->Type->ChangeVariable; + target.Variable[var].Enable = 1; + target.Variable[var].Value += missile->Type->ChangeAmount; + if (target.Variable[var].Value > target.Variable[var].Max && missile->Type->ChangeMax) { + target.Variable[var].Max = target.Variable[var].Value; + } + } + // Show impact missiles if (target.Variable[SHIELD_INDEX].Value > 0 && !target.Type->Impact[ANIMATIONS_DEATHTYPES + 1].Name.empty()) { // shield impact diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp index 652d1e8fa..0de9886cb 100644 --- a/src/unit/unittype.cpp +++ b/src/unit/unittype.cpp @@ -368,7 +368,7 @@ static bool SaveUnitStats(const CUnitStats &stats, const CUnitType &type, int pl if (stats == type.DefaultStat) { return false; } - file.printf("DefineUnitStats(\"%s\", %d,\n ", type.Ident.c_str(), plynr); + file.printf("DefineUnitStats(\"%s\", %d, {\n ", type.Ident.c_str(), plynr); for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) { file.printf("\"%s\", {Value = %d, Max = %d, Increase = %d%s},\n ", UnitTypeVar.VariableNameLookup[i], stats.Variables[i].Value, @@ -382,14 +382,14 @@ static bool SaveUnitStats(const CUnitStats &stats, const CUnitType &type, int pl } file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Costs[i]); } - file.printf("\"storing\", {"); + file.printf("},\n\"storing\", {"); for (unsigned int i = 0; i < MaxCosts; ++i) { if (i) { file.printf(" "); } file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Storing[i]); } - file.printf("})\n"); + file.printf("}})\n"); return true; }