/** ** Player has the quantity of rescued unit-type near to unit-type. */ static int CclIfRescuedNearUnit(lua_State *l) { LuaCheckArgs(l, 5); lua_pushvalue(l, 1); const int plynr = TriggerGetPlayer(l); lua_pop(l, 1); const char *op = LuaToString(l, 2); const int q = LuaToNumber(l, 3); lua_pushvalue(l, 4); const CUnitType *unittype = TriggerGetUnitType(l); lua_pop(l, 1); const CUnitType *ut2 = CclGetUnitType(l); if (!unittype || !ut2) { LuaError(l, "CclIfRescuedNearUnit: not a unit-type valid"); } CompareFunction compare = GetCompareFunction(op); if (!compare) { LuaError(l, "Illegal comparison operation in if-rescued-near-unit: %s" _C_ op); } // Get all unit types 'near'. std::vector<CUnit *> table; FindUnitsByType(*ut2, table); for (size_t i = 0; i != table.size(); ++i) { CUnit ¢erUnit = *table[i]; std::vector<CUnit *> around; SelectAroundUnit(centerUnit, 1, around); // Count the requested units int s = 0; for (size_t j = 0; j != around.size(); ++j) { CUnit &unit = *around[j]; if (unit.RescuedFrom) { // only rescued units // Check unit type if (unittype == ANY_UNIT || (unittype == ALL_FOODUNITS && !unit.Type->Building) || (unittype == ALL_BUILDINGS && unit.Type->Building) || (unittype == unit.Type)) { // Check the player if (plynr == -1 || plynr == unit.Player->Index) { ++s; } } } } if (compare(s, q)) { lua_pushboolean(l, 1); return 1; } } lua_pushboolean(l, 0); return 1; }
/** ** Apply the modifiers of an upgrade. ** ** This function will mark upgrade done and do all required modifications ** to unit types and will modify allow/forbid maps ** ** @param player Player that get all the upgrades. ** @param um Upgrade modifier that do the effects */ static void ApplyUpgradeModifier(CPlayer *player, const CUpgradeModifier *um) { int z; // iterator on upgrade or unittype. int j; // iterator on cost or variable. int pn; // player number. int varModified; // 0 if variable is not modified. int numunits; // number of unit of the current type. CUnit *unitupgrade[UnitMax]; // array of unit of the current type CUnit *unit; // current unit. Assert(player); Assert(um); pn = player->Index; for (z = 0; z < UpgradeMax; ++z) { // allow/forbid upgrades for player. only if upgrade is not acquired // FIXME: check if modify is allowed if (player->Allow.Upgrades[z] != 'R') { if (um->ChangeUpgrades[z] == 'A') { player->Allow.Upgrades[z] = 'A'; } if (um->ChangeUpgrades[z] == 'F') { player->Allow.Upgrades[z] = 'F'; } // we can even have upgrade acquired w/o costs if (um->ChangeUpgrades[z] == 'R') { player->Allow.Upgrades[z] = 'R'; } } } for (z = 0; z < UnitTypeMax; ++z) { // add/remove allowed units // FIXME: check if modify is allowed player->Allow.Units[z] += um->ChangeUnits[z]; Assert(um->ApplyTo[z] == '?' || um->ApplyTo[z] == 'X'); // this modifier should be applied to unittype id == z if (um->ApplyTo[z] == 'X') { // If Sight range is upgraded, we need to change EVERY unit // to the new range, otherwise the counters get confused. if (um->Modifier.Variables[SIGHTRANGE_INDEX].Value) { numunits = FindUnitsByType(UnitTypes[z], unitupgrade); for (numunits--; numunits >= 0; --numunits) { unit = unitupgrade[numunits]; if (unit->Player->Index == pn && !unit->Removed) { MapUnmarkUnitSight(unit); unit->CurrentSightRange = UnitTypes[z]->Stats[pn].Variables[SIGHTRANGE_INDEX].Max + um->Modifier.Variables[SIGHTRANGE_INDEX].Value; MapMarkUnitSight(unit); } } } // upgrade costs :) for (j = 0; j < MaxCosts; ++j) { UnitTypes[z]->Stats[pn].Costs[j] += um->Modifier.Costs[j]; } varModified = 0; for (j = 0; j < UnitTypeVar.NumberVariable; j++) { varModified |= um->Modifier.Variables[j].Value | um->Modifier.Variables[j].Max | um->Modifier.Variables[j].Increase; UnitTypes[z]->Stats[pn].Variables[j].Value += um->Modifier.Variables[j].Value; if (UnitTypes[z]->Stats[pn].Variables[j].Value < 0) { UnitTypes[z]->Stats[pn].Variables[j].Value = 0; } UnitTypes[z]->Stats[pn].Variables[j].Max += um->Modifier.Variables[j].Max; if (UnitTypes[z]->Stats[pn].Variables[j].Max < 0) { UnitTypes[z]->Stats[pn].Variables[j].Max = 0; } if (UnitTypes[z]->Stats[pn].Variables[j].Value > UnitTypes[z]->Stats[pn].Variables[j].Max) { UnitTypes[z]->Stats[pn].Variables[j].Value = UnitTypes[z]->Stats[pn].Variables[j].Max; } UnitTypes[z]->Stats[pn].Variables[j].Increase += um->Modifier.Variables[j].Increase; } // And now modify ingame units if (varModified) { numunits = FindUnitsByType(UnitTypes[z], unitupgrade); numunits--; // Change to 0 Start not 1 start for (; numunits >= 0; --numunits) { unit = unitupgrade[numunits]; if (unit->Player->Index != player->Index) { continue; } for (j = 0; j < UnitTypeVar.NumberVariable; j++) { unit->Variable[j].Value += um->Modifier.Variables[j].Value; if (unit->Variable[j].Value < 0) { unit->Variable[j].Value = 0; } unit->Variable[j].Max += um->Modifier.Variables[j].Max; if (unit->Variable[j].Max < 0) { unit->Variable[j].Max = 0; } if (unit->Variable[j].Value > unit->Variable[j].Max) { unit->Variable[j].Value = unit->Variable[j].Max; } unit->Variable[j].Increase += um->Modifier.Variables[j].Increase; } } } if (um->ConvertTo) { ConvertUnitTypeTo(player,UnitTypes[z], um->ConvertTo); } } } }
/** ** Remove the modifiers of an upgrade. ** ** This function will unmark upgrade as done and undo all required modifications ** to unit types and will modify allow/forbid maps back ** ** @param player Player that get all the upgrades. ** @param um Upgrade modifier that do the effects */ static void RemoveUpgradeModifier(CPlayer &player, const CUpgradeModifier *um) { Assert(um); int pn = player.Index; if (um->SpeedResearch != 0) { player.SpeedResearch -= um->SpeedResearch; } for (int z = 0; z < UpgradeMax; ++z) { // allow/forbid upgrades for player. only if upgrade is not acquired // FIXME: check if modify is allowed if (player.Allow.Upgrades[z] != 'R') { if (um->ChangeUpgrades[z] == 'A') { player.Allow.Upgrades[z] = 'F'; } if (um->ChangeUpgrades[z] == 'F') { player.Allow.Upgrades[z] = 'A'; } // we can even have upgrade acquired w/o costs if (um->ChangeUpgrades[z] == 'R') { player.Allow.Upgrades[z] = 'A'; } } } for (size_t z = 0; z < UnitTypes.size(); ++z) { CUnitStats &stat = UnitTypes[z]->Stats[pn]; // add/remove allowed units // FIXME: check if modify is allowed player.Allow.Units[z] -= um->ChangeUnits[z]; Assert(um->ApplyTo[z] == '?' || um->ApplyTo[z] == 'X'); // this modifier should be applied to unittype id == z if (um->ApplyTo[z] == 'X') { // If Sight range is upgraded, we need to change EVERY unit // to the new range, otherwise the counters get confused. if (um->Modifier.Variables[SIGHTRANGE_INDEX].Value) { std::vector<CUnit *> unitupgrade; FindUnitsByType(*UnitTypes[z], unitupgrade); for (size_t j = 0; j != unitupgrade.size(); ++j) { CUnit &unit = *unitupgrade[j]; if (unit.Player->Index == pn && !unit.Removed) { MapUnmarkUnitSight(unit); unit.CurrentSightRange = stat.Variables[SIGHTRANGE_INDEX].Max - um->Modifier.Variables[SIGHTRANGE_INDEX].Value; MapMarkUnitSight(unit); } } } // upgrade costs :) for (unsigned int j = 0; j < MaxCosts; ++j) { stat.Costs[j] -= um->Modifier.Costs[j]; stat.Storing[j] -= um->Modifier.Storing[j]; } int varModified = 0; for (unsigned int j = 0; j < UnitTypeVar.GetNumberVariable(); j++) { varModified |= um->Modifier.Variables[j].Value | um->Modifier.Variables[j].Max | um->Modifier.Variables[j].Increase | um->Modifier.Variables[j].Enable | um->ModifyPercent[j]; stat.Variables[j].Enable |= um->Modifier.Variables[j].Enable; if (um->ModifyPercent[j]) { stat.Variables[j].Value = stat.Variables[j].Value * 100 / (100 + um->ModifyPercent[j]); stat.Variables[j].Max = stat.Variables[j].Max * 100 / (100 + um->ModifyPercent[j]); } else { stat.Variables[j].Value -= um->Modifier.Variables[j].Value; stat.Variables[j].Max -= um->Modifier.Variables[j].Max; stat.Variables[j].Increase -= um->Modifier.Variables[j].Increase; } stat.Variables[j].Max = std::max(stat.Variables[j].Max, 0); clamp(&stat.Variables[j].Value, 0, stat.Variables[j].Max); } // And now modify ingame units if (varModified) { std::vector<CUnit *> unitupgrade; FindUnitsByType(*UnitTypes[z], unitupgrade, true); for (size_t j = 0; j != unitupgrade.size(); ++j) { CUnit &unit = *unitupgrade[j]; if (unit.Player->Index != player.Index) { continue; } for (unsigned int j = 0; j < UnitTypeVar.GetNumberVariable(); j++) { unit.Variable[j].Enable |= um->Modifier.Variables[j].Enable; if (um->ModifyPercent[j]) { unit.Variable[j].Value = unit.Variable[j].Value * 100 / (100 + um->ModifyPercent[j]); unit.Variable[j].Max = unit.Variable[j].Max * 100 / (100 + um->ModifyPercent[j]); } else { unit.Variable[j].Value -= um->Modifier.Variables[j].Value; unit.Variable[j].Increase -= um->Modifier.Variables[j].Increase; } unit.Variable[j].Max -= um->Modifier.Variables[j].Max; unit.Variable[j].Max = std::max(unit.Variable[j].Max, 0); clamp(&unit.Variable[j].Value, 0, unit.Variable[j].Max); } } } if (um->ConvertTo) { ConvertUnitTypeTo(player, *um->ConvertTo, *UnitTypes[z]); } } } }