mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
rename; introduce factor
This commit is contained in:
@@ -249,9 +249,9 @@ int CBattleCallback::sendRequest(const CPackForServer * request)
|
|||||||
return requestID;
|
return requestID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCallback::spellResearch( const CGTownInstance *town, SpellID spellAtSlot )
|
void CCallback::spellResearch( const CGTownInstance *town, SpellID spellAtSlot, bool accepted )
|
||||||
{
|
{
|
||||||
SpellResearch pack(town->id, spellAtSlot);
|
SpellResearch pack(town->id, spellAtSlot, accepted);
|
||||||
sendRequest(&pack);
|
sendRequest(&pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -78,7 +78,7 @@ public:
|
|||||||
virtual bool visitTownBuilding(const CGTownInstance *town, BuildingID buildingID)=0;
|
virtual bool visitTownBuilding(const CGTownInstance *town, BuildingID buildingID)=0;
|
||||||
virtual void recruitCreatures(const CGDwelling *obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1)=0;
|
virtual void recruitCreatures(const CGDwelling *obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1)=0;
|
||||||
virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made
|
virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made
|
||||||
virtual void spellResearch(const CGTownInstance *town, SpellID spellAtSlot)=0;
|
virtual void spellResearch(const CGTownInstance *town, SpellID spellAtSlot, bool accepted)=0;
|
||||||
virtual void swapGarrisonHero(const CGTownInstance *town)=0;
|
virtual void swapGarrisonHero(const CGTownInstance *town)=0;
|
||||||
|
|
||||||
virtual void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
|
virtual void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
|
||||||
@@ -188,7 +188,7 @@ public:
|
|||||||
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override;
|
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override;
|
||||||
bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override;
|
bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override;
|
||||||
void endTurn() override;
|
void endTurn() override;
|
||||||
void spellResearch(const CGTownInstance *town, SpellID spellAtSlot) override;
|
void spellResearch(const CGTownInstance *town, SpellID spellAtSlot, bool accepted) override;
|
||||||
void swapGarrisonHero(const CGTownInstance *town) override;
|
void swapGarrisonHero(const CGTownInstance *town) override;
|
||||||
void buyArtifact(const CGHeroInstance *hero, ArtifactID aid) override;
|
void buyArtifact(const CGHeroInstance *hero, ArtifactID aid) override;
|
||||||
void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override;
|
void trade(const ObjectInstanceID marketId, EMarketMode mode, TradeItemSell id1, TradeItemBuy id2, ui32 val1, const CGHeroInstance * hero = nullptr) override;
|
||||||
|
@@ -159,7 +159,7 @@ public:
|
|||||||
friend class CBattleCallback; //handling players actions
|
friend class CBattleCallback; //handling players actions
|
||||||
|
|
||||||
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {};
|
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {};
|
||||||
void setTownSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells) override {};
|
void setResearchedSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells, bool accepted) override {};
|
||||||
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;};
|
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;};
|
||||||
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {};
|
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {};
|
||||||
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
|
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
|
||||||
|
@@ -37,7 +37,7 @@ public:
|
|||||||
void visitHeroVisitCastle(HeroVisitCastle & pack) override;
|
void visitHeroVisitCastle(HeroVisitCastle & pack) override;
|
||||||
void visitSetMana(SetMana & pack) override;
|
void visitSetMana(SetMana & pack) override;
|
||||||
void visitSetMovePoints(SetMovePoints & pack) override;
|
void visitSetMovePoints(SetMovePoints & pack) override;
|
||||||
void visitSetTownSpells(SetTownSpells & pack) override;
|
void visitSetResearchedSpells(SetResearchedSpells & pack) override;
|
||||||
void visitFoWChange(FoWChange & pack) override;
|
void visitFoWChange(FoWChange & pack) override;
|
||||||
void visitChangeStackCount(ChangeStackCount & pack) override;
|
void visitChangeStackCount(ChangeStackCount & pack) override;
|
||||||
void visitSetStackType(SetStackType & pack) override;
|
void visitSetStackType(SetStackType & pack) override;
|
||||||
|
@@ -173,7 +173,7 @@ void ApplyClientNetPackVisitor::visitSetMovePoints(SetMovePoints & pack)
|
|||||||
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroMovePointsChanged, h);
|
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroMovePointsChanged, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitSetTownSpells(SetTownSpells & pack)
|
void ApplyClientNetPackVisitor::visitSetResearchedSpells(SetResearchedSpells & pack)
|
||||||
{
|
{
|
||||||
for(const auto & win : GH.windows().findWindows<CMageGuildScreen>())
|
for(const auto & win : GH.windows().findWindows<CMageGuildScreen>())
|
||||||
win->updateSpells();
|
win->updateSpells();
|
||||||
|
@@ -2047,7 +2047,7 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
|
|||||||
|
|
||||||
auto costBase = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE));
|
auto costBase = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE));
|
||||||
auto costPerLevel = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL));
|
auto costPerLevel = TResources(LOCPLINT->cb->getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL));
|
||||||
auto cost = costBase + costPerLevel * (level + 1);
|
auto cost = (costBase + costPerLevel * (level + 1)) * (town->spellResearchCounter + 1);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CComponent>> resComps;
|
std::vector<std::shared_ptr<CComponent>> resComps;
|
||||||
resComps.push_back(std::make_shared<CComponent>(ComponentType::SPELL, town->spells[level].at(town->spellsAtLevel(level, false))));
|
resComps.push_back(std::make_shared<CComponent>(ComponentType::SPELL, town->spells[level].at(town->spellsAtLevel(level, false))));
|
||||||
@@ -2058,7 +2058,7 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(LOCPLINT->cb->getResourceAmount().canAfford(cost))
|
if(LOCPLINT->cb->getResourceAmount().canAfford(cost))
|
||||||
LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.spellResearch.pay"), [this, town](){ LOCPLINT->cb->spellResearch(town, spell->id); }, nullptr, resComps);
|
LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.spellResearch.pay"), [this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, true); }, nullptr, resComps);
|
||||||
else
|
else
|
||||||
LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.spellResearch.canNotAfford"), resComps);
|
LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.spellResearch.canNotAfford"), resComps);
|
||||||
}
|
}
|
||||||
|
@@ -302,7 +302,7 @@
|
|||||||
"backpackSize" : -1,
|
"backpackSize" : -1,
|
||||||
// if heroes are invitable in tavern
|
// if heroes are invitable in tavern
|
||||||
"tavernInvite" : false,
|
"tavernInvite" : false,
|
||||||
// minimai primary skills for heroes
|
// minimal primary skills for heroes
|
||||||
"minimalPrimarySkills": [ 0, 0, 1, 1]
|
"minimalPrimarySkills": [ 0, 0, 1, 1]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -317,7 +317,9 @@
|
|||||||
// Base cost for an spell research
|
// Base cost for an spell research
|
||||||
"spellResearchCostBase": { "gold": 1000 },
|
"spellResearchCostBase": { "gold": 1000 },
|
||||||
// Costs depends on level for an spell research
|
// Costs depends on level for an spell research
|
||||||
"spellResearchCostPerLevel": { "wood" : 2, "mercury": 2, "ore": 2, "sulfur": 2, "crystal": 2, "gems": 2 }
|
"spellResearchCostPerLevel": { "wood" : 2, "mercury": 2, "ore": 2, "sulfur": 2, "crystal": 2, "gems": 2 },
|
||||||
|
// Factor for increasing cost for each research
|
||||||
|
"spellResearchCostFactorPerResearch": 2.0
|
||||||
},
|
},
|
||||||
|
|
||||||
"combat":
|
"combat":
|
||||||
|
@@ -51,11 +51,12 @@
|
|||||||
"type" : "object",
|
"type" : "object",
|
||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"buildingsPerTurnCap" : { "type" : "number" },
|
"buildingsPerTurnCap" : { "type" : "number" },
|
||||||
"startingDwellingChances" : { "type" : "array" },
|
"startingDwellingChances" : { "type" : "array" },
|
||||||
"spellResearch" : { "type" : "boolean" },
|
"spellResearch" : { "type" : "boolean" },
|
||||||
"spellResearchCostBase" : { "type" : "object" },
|
"spellResearchCostBase" : { "type" : "object" },
|
||||||
"spellResearchCostPerLevel" : { "type" : "object" }
|
"spellResearchCostPerLevel" : { "type" : "object" },
|
||||||
|
"spellResearchCostFactorPerResearch" : { "type" : "number" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"combat": {
|
"combat": {
|
||||||
|
@@ -37,73 +37,74 @@ GameSettings::GameSettings() = default;
|
|||||||
GameSettings::~GameSettings() = default;
|
GameSettings::~GameSettings() = default;
|
||||||
|
|
||||||
const std::vector<GameSettings::SettingOption> GameSettings::settingProperties = {
|
const std::vector<GameSettings::SettingOption> GameSettings::settingProperties = {
|
||||||
{EGameSettings::BANKS_SHOW_GUARDS_COMPOSITION, "banks", "showGuardsComposition" },
|
{EGameSettings::BANKS_SHOW_GUARDS_COMPOSITION, "banks", "showGuardsComposition" },
|
||||||
{EGameSettings::BONUSES_GLOBAL, "bonuses", "global" },
|
{EGameSettings::BONUSES_GLOBAL, "bonuses", "global" },
|
||||||
{EGameSettings::BONUSES_PER_HERO, "bonuses", "perHero" },
|
{EGameSettings::BONUSES_PER_HERO, "bonuses", "perHero" },
|
||||||
{EGameSettings::COMBAT_AREA_SHOT_CAN_TARGET_EMPTY_HEX, "combat", "areaShotCanTargetEmptyHex" },
|
{EGameSettings::COMBAT_AREA_SHOT_CAN_TARGET_EMPTY_HEX, "combat", "areaShotCanTargetEmptyHex" },
|
||||||
{EGameSettings::COMBAT_ATTACK_POINT_DAMAGE_FACTOR, "combat", "attackPointDamageFactor" },
|
{EGameSettings::COMBAT_ATTACK_POINT_DAMAGE_FACTOR, "combat", "attackPointDamageFactor" },
|
||||||
{EGameSettings::COMBAT_ATTACK_POINT_DAMAGE_FACTOR_CAP, "combat", "attackPointDamageFactorCap" },
|
{EGameSettings::COMBAT_ATTACK_POINT_DAMAGE_FACTOR_CAP, "combat", "attackPointDamageFactorCap" },
|
||||||
{EGameSettings::COMBAT_BAD_LUCK_DICE, "combat", "badLuckDice" },
|
{EGameSettings::COMBAT_BAD_LUCK_DICE, "combat", "badLuckDice" },
|
||||||
{EGameSettings::COMBAT_BAD_MORALE_DICE, "combat", "badMoraleDice" },
|
{EGameSettings::COMBAT_BAD_MORALE_DICE, "combat", "badMoraleDice" },
|
||||||
{EGameSettings::COMBAT_DEFENSE_POINT_DAMAGE_FACTOR, "combat", "defensePointDamageFactor" },
|
{EGameSettings::COMBAT_DEFENSE_POINT_DAMAGE_FACTOR, "combat", "defensePointDamageFactor" },
|
||||||
{EGameSettings::COMBAT_DEFENSE_POINT_DAMAGE_FACTOR_CAP, "combat", "defensePointDamageFactorCap" },
|
{EGameSettings::COMBAT_DEFENSE_POINT_DAMAGE_FACTOR_CAP, "combat", "defensePointDamageFactorCap" },
|
||||||
{EGameSettings::COMBAT_GOOD_LUCK_DICE, "combat", "goodLuckDice" },
|
{EGameSettings::COMBAT_GOOD_LUCK_DICE, "combat", "goodLuckDice" },
|
||||||
{EGameSettings::COMBAT_GOOD_MORALE_DICE, "combat", "goodMoraleDice" },
|
{EGameSettings::COMBAT_GOOD_MORALE_DICE, "combat", "goodMoraleDice" },
|
||||||
{EGameSettings::COMBAT_LAYOUTS, "combat", "layouts" },
|
{EGameSettings::COMBAT_LAYOUTS, "combat", "layouts" },
|
||||||
{EGameSettings::COMBAT_ONE_HEX_TRIGGERS_OBSTACLES, "combat", "oneHexTriggersObstacles" },
|
{EGameSettings::COMBAT_ONE_HEX_TRIGGERS_OBSTACLES, "combat", "oneHexTriggersObstacles" },
|
||||||
{EGameSettings::CREATURES_ALLOW_ALL_FOR_DOUBLE_MONTH, "creatures", "allowAllForDoubleMonth" },
|
{EGameSettings::CREATURES_ALLOW_ALL_FOR_DOUBLE_MONTH, "creatures", "allowAllForDoubleMonth" },
|
||||||
{EGameSettings::CREATURES_ALLOW_RANDOM_SPECIAL_WEEKS, "creatures", "allowRandomSpecialWeeks" },
|
{EGameSettings::CREATURES_ALLOW_RANDOM_SPECIAL_WEEKS, "creatures", "allowRandomSpecialWeeks" },
|
||||||
{EGameSettings::CREATURES_DAILY_STACK_EXPERIENCE, "creatures", "dailyStackExperience" },
|
{EGameSettings::CREATURES_DAILY_STACK_EXPERIENCE, "creatures", "dailyStackExperience" },
|
||||||
{EGameSettings::CREATURES_WEEKLY_GROWTH_CAP, "creatures", "weeklyGrowthCap" },
|
{EGameSettings::CREATURES_WEEKLY_GROWTH_CAP, "creatures", "weeklyGrowthCap" },
|
||||||
{EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT, "creatures", "weeklyGrowthPercent" },
|
{EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT, "creatures", "weeklyGrowthPercent" },
|
||||||
{EGameSettings::DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE, "spells", "dimensionDoorExposesTerrainType" },
|
{EGameSettings::DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE, "spells", "dimensionDoorExposesTerrainType" },
|
||||||
{EGameSettings::DIMENSION_DOOR_FAILURE_SPENDS_POINTS, "spells", "dimensionDoorFailureSpendsPoints" },
|
{EGameSettings::DIMENSION_DOOR_FAILURE_SPENDS_POINTS, "spells", "dimensionDoorFailureSpendsPoints" },
|
||||||
{EGameSettings::DIMENSION_DOOR_ONLY_TO_UNCOVERED_TILES, "spells", "dimensionDoorOnlyToUncoveredTiles"},
|
{EGameSettings::DIMENSION_DOOR_ONLY_TO_UNCOVERED_TILES, "spells", "dimensionDoorOnlyToUncoveredTiles" },
|
||||||
{EGameSettings::DIMENSION_DOOR_TOURNAMENT_RULES_LIMIT, "spells", "dimensionDoorTournamentRulesLimit"},
|
{EGameSettings::DIMENSION_DOOR_TOURNAMENT_RULES_LIMIT, "spells", "dimensionDoorTournamentRulesLimit" },
|
||||||
{EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS, "spells", "dimensionDoorTriggersGuards" },
|
{EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS, "spells", "dimensionDoorTriggersGuards" },
|
||||||
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL, "dwellings", "accumulateWhenNeutral" },
|
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL, "dwellings", "accumulateWhenNeutral" },
|
||||||
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED, "dwellings", "accumulateWhenOwned" },
|
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED, "dwellings", "accumulateWhenOwned" },
|
||||||
{EGameSettings::DWELLINGS_MERGE_ON_RECRUIT, "dwellings", "mergeOnRecruit" },
|
{EGameSettings::DWELLINGS_MERGE_ON_RECRUIT, "dwellings", "mergeOnRecruit" },
|
||||||
{EGameSettings::HEROES_BACKPACK_CAP, "heroes", "backpackSize" },
|
{EGameSettings::HEROES_BACKPACK_CAP, "heroes", "backpackSize" },
|
||||||
{EGameSettings::HEROES_MINIMAL_PRIMARY_SKILLS, "heroes", "minimalPrimarySkills" },
|
{EGameSettings::HEROES_MINIMAL_PRIMARY_SKILLS, "heroes", "minimalPrimarySkills" },
|
||||||
{EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP, "heroes", "perPlayerOnMapCap" },
|
{EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP, "heroes", "perPlayerOnMapCap" },
|
||||||
{EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP, "heroes", "perPlayerTotalCap" },
|
{EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP, "heroes", "perPlayerTotalCap" },
|
||||||
{EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS, "heroes", "retreatOnWinWithoutTroops" },
|
{EGameSettings::HEROES_RETREAT_ON_WIN_WITHOUT_TROOPS, "heroes", "retreatOnWinWithoutTroops" },
|
||||||
{EGameSettings::HEROES_STARTING_STACKS_CHANCES, "heroes", "startingStackChances" },
|
{EGameSettings::HEROES_STARTING_STACKS_CHANCES, "heroes", "startingStackChances" },
|
||||||
{EGameSettings::HEROES_TAVERN_INVITE, "heroes", "tavernInvite" },
|
{EGameSettings::HEROES_TAVERN_INVITE, "heroes", "tavernInvite" },
|
||||||
{EGameSettings::MAP_FORMAT_ARMAGEDDONS_BLADE, "mapFormat", "armageddonsBlade" },
|
{EGameSettings::MAP_FORMAT_ARMAGEDDONS_BLADE, "mapFormat", "armageddonsBlade" },
|
||||||
{EGameSettings::MAP_FORMAT_CHRONICLES, "mapFormat", "chronicles" },
|
{EGameSettings::MAP_FORMAT_CHRONICLES, "mapFormat", "chronicles" },
|
||||||
{EGameSettings::MAP_FORMAT_HORN_OF_THE_ABYSS, "mapFormat", "hornOfTheAbyss" },
|
{EGameSettings::MAP_FORMAT_HORN_OF_THE_ABYSS, "mapFormat", "hornOfTheAbyss" },
|
||||||
{EGameSettings::MAP_FORMAT_IN_THE_WAKE_OF_GODS, "mapFormat", "inTheWakeOfGods" },
|
{EGameSettings::MAP_FORMAT_IN_THE_WAKE_OF_GODS, "mapFormat", "inTheWakeOfGods" },
|
||||||
{EGameSettings::MAP_FORMAT_JSON_VCMI, "mapFormat", "jsonVCMI" },
|
{EGameSettings::MAP_FORMAT_JSON_VCMI, "mapFormat", "jsonVCMI" },
|
||||||
{EGameSettings::MAP_FORMAT_RESTORATION_OF_ERATHIA, "mapFormat", "restorationOfErathia" },
|
{EGameSettings::MAP_FORMAT_RESTORATION_OF_ERATHIA, "mapFormat", "restorationOfErathia" },
|
||||||
{EGameSettings::MAP_FORMAT_SHADOW_OF_DEATH, "mapFormat", "shadowOfDeath" },
|
{EGameSettings::MAP_FORMAT_SHADOW_OF_DEATH, "mapFormat", "shadowOfDeath" },
|
||||||
{EGameSettings::MARKETS_BLACK_MARKET_RESTOCK_PERIOD, "markets", "blackMarketRestockPeriod" },
|
{EGameSettings::MARKETS_BLACK_MARKET_RESTOCK_PERIOD, "markets", "blackMarketRestockPeriod" },
|
||||||
{EGameSettings::MODULE_COMMANDERS, "modules", "commanders" },
|
{EGameSettings::MODULE_COMMANDERS, "modules", "commanders" },
|
||||||
{EGameSettings::MODULE_STACK_ARTIFACT, "modules", "stackArtifact" },
|
{EGameSettings::MODULE_STACK_ARTIFACT, "modules", "stackArtifact" },
|
||||||
{EGameSettings::MODULE_STACK_EXPERIENCE, "modules", "stackExperience" },
|
{EGameSettings::MODULE_STACK_EXPERIENCE, "modules", "stackExperience" },
|
||||||
{EGameSettings::PATHFINDER_IGNORE_GUARDS, "pathfinder", "ignoreGuards" },
|
{EGameSettings::PATHFINDER_IGNORE_GUARDS, "pathfinder", "ignoreGuards" },
|
||||||
{EGameSettings::PATHFINDER_ORIGINAL_FLY_RULES, "pathfinder", "originalFlyRules" },
|
{EGameSettings::PATHFINDER_ORIGINAL_FLY_RULES, "pathfinder", "originalFlyRules" },
|
||||||
{EGameSettings::PATHFINDER_USE_BOAT, "pathfinder", "useBoat" },
|
{EGameSettings::PATHFINDER_USE_BOAT, "pathfinder", "useBoat" },
|
||||||
{EGameSettings::PATHFINDER_USE_MONOLITH_ONE_WAY_RANDOM, "pathfinder", "useMonolithOneWayRandom" },
|
{EGameSettings::PATHFINDER_USE_MONOLITH_ONE_WAY_RANDOM, "pathfinder", "useMonolithOneWayRandom" },
|
||||||
{EGameSettings::PATHFINDER_USE_MONOLITH_ONE_WAY_UNIQUE, "pathfinder", "useMonolithOneWayUnique" },
|
{EGameSettings::PATHFINDER_USE_MONOLITH_ONE_WAY_UNIQUE, "pathfinder", "useMonolithOneWayUnique" },
|
||||||
{EGameSettings::PATHFINDER_USE_MONOLITH_TWO_WAY, "pathfinder", "useMonolithTwoWay" },
|
{EGameSettings::PATHFINDER_USE_MONOLITH_TWO_WAY, "pathfinder", "useMonolithTwoWay" },
|
||||||
{EGameSettings::PATHFINDER_USE_WHIRLPOOL, "pathfinder", "useWhirlpool" },
|
{EGameSettings::PATHFINDER_USE_WHIRLPOOL, "pathfinder", "useWhirlpool" },
|
||||||
{EGameSettings::TEXTS_ARTIFACT, "textData", "artifact" },
|
{EGameSettings::TEXTS_ARTIFACT, "textData", "artifact" },
|
||||||
{EGameSettings::TEXTS_CREATURE, "textData", "creature" },
|
{EGameSettings::TEXTS_CREATURE, "textData", "creature" },
|
||||||
{EGameSettings::TEXTS_FACTION, "textData", "faction" },
|
{EGameSettings::TEXTS_FACTION, "textData", "faction" },
|
||||||
{EGameSettings::TEXTS_HERO, "textData", "hero" },
|
{EGameSettings::TEXTS_HERO, "textData", "hero" },
|
||||||
{EGameSettings::TEXTS_HERO_CLASS, "textData", "heroClass" },
|
{EGameSettings::TEXTS_HERO_CLASS, "textData", "heroClass" },
|
||||||
{EGameSettings::TEXTS_OBJECT, "textData", "object" },
|
{EGameSettings::TEXTS_OBJECT, "textData", "object" },
|
||||||
{EGameSettings::TEXTS_RIVER, "textData", "river" },
|
{EGameSettings::TEXTS_RIVER, "textData", "river" },
|
||||||
{EGameSettings::TEXTS_ROAD, "textData", "road" },
|
{EGameSettings::TEXTS_ROAD, "textData", "road" },
|
||||||
{EGameSettings::TEXTS_SPELL, "textData", "spell" },
|
{EGameSettings::TEXTS_SPELL, "textData", "spell" },
|
||||||
{EGameSettings::TEXTS_TERRAIN, "textData", "terrain" },
|
{EGameSettings::TEXTS_TERRAIN, "textData", "terrain" },
|
||||||
{EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP, "towns", "buildingsPerTurnCap" },
|
{EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP, "towns", "buildingsPerTurnCap" },
|
||||||
{EGameSettings::TOWNS_STARTING_DWELLING_CHANCES, "towns", "startingDwellingChances" },
|
{EGameSettings::TOWNS_STARTING_DWELLING_CHANCES, "towns", "startingDwellingChances" },
|
||||||
{EGameSettings::TOWNS_SPELL_RESEARCH, "towns", "spellResearch" },
|
{EGameSettings::TOWNS_SPELL_RESEARCH, "towns", "spellResearch" },
|
||||||
{EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE, "towns", "spellResearchCostBase" },
|
{EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE, "towns", "spellResearchCostBase" },
|
||||||
{EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL, "towns", "spellResearchCostPerLevel" },
|
{EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL, "towns", "spellResearchCostPerLevel" },
|
||||||
|
{EGameSettings::TOWNS_SPELL_RESEARCH_COST_FACTOR_PER_RESEARCH, "towns", "spellResearchCostFactorPerResearch" },
|
||||||
};
|
};
|
||||||
|
|
||||||
void GameSettings::loadBase(const JsonNode & input)
|
void GameSettings::loadBase(const JsonNode & input)
|
||||||
|
@@ -94,7 +94,7 @@ public:
|
|||||||
virtual void showInfoDialog(InfoWindow * iw) = 0;
|
virtual void showInfoDialog(InfoWindow * iw) = 0;
|
||||||
|
|
||||||
virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells)=0;
|
virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells)=0;
|
||||||
virtual void setTownSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells)=0;
|
virtual void setResearchedSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells, bool accepted)=0;
|
||||||
virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
|
virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
|
||||||
virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
|
virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
|
||||||
virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0;
|
virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0;
|
||||||
|
@@ -82,6 +82,7 @@ enum class EGameSettings
|
|||||||
TOWNS_SPELL_RESEARCH,
|
TOWNS_SPELL_RESEARCH,
|
||||||
TOWNS_SPELL_RESEARCH_COST_BASE,
|
TOWNS_SPELL_RESEARCH_COST_BASE,
|
||||||
TOWNS_SPELL_RESEARCH_COST_PER_LEVEL,
|
TOWNS_SPELL_RESEARCH_COST_PER_LEVEL,
|
||||||
|
TOWNS_SPELL_RESEARCH_COST_FACTOR_PER_RESEARCH,
|
||||||
|
|
||||||
OPTIONS_COUNT,
|
OPTIONS_COUNT,
|
||||||
OPTIONS_BEGIN = BONUSES_GLOBAL
|
OPTIONS_BEGIN = BONUSES_GLOBAL
|
||||||
|
@@ -270,6 +270,7 @@ CGTownInstance::CGTownInstance(IGameCallback *cb):
|
|||||||
identifier(0),
|
identifier(0),
|
||||||
alignmentToPlayer(PlayerColor::NEUTRAL),
|
alignmentToPlayer(PlayerColor::NEUTRAL),
|
||||||
lastSpellResearchDay(0),
|
lastSpellResearchDay(0),
|
||||||
|
spellResearchCounter(0),
|
||||||
spellResearchAllowed(true)
|
spellResearchAllowed(true)
|
||||||
{
|
{
|
||||||
this->setNodeType(CBonusSystemNode::TOWN);
|
this->setNodeType(CBonusSystemNode::TOWN);
|
||||||
|
@@ -74,6 +74,7 @@ public:
|
|||||||
std::vector<CCastleEvent> events;
|
std::vector<CCastleEvent> events;
|
||||||
std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond, factory = save debts);
|
std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond, factory = save debts);
|
||||||
int lastSpellResearchDay;
|
int lastSpellResearchDay;
|
||||||
|
int spellResearchCounter;
|
||||||
bool spellResearchAllowed;
|
bool spellResearchAllowed;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -96,7 +97,11 @@ public:
|
|||||||
h & events;
|
h & events;
|
||||||
|
|
||||||
if (h.version >= Handler::Version::SPELL_RESEARCH)
|
if (h.version >= Handler::Version::SPELL_RESEARCH)
|
||||||
|
{
|
||||||
h & lastSpellResearchDay;
|
h & lastSpellResearchDay;
|
||||||
|
h & spellResearchCounter;
|
||||||
|
h & spellResearchAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
if (h.version >= Handler::Version::NEW_TOWN_BUILDINGS)
|
if (h.version >= Handler::Version::NEW_TOWN_BUILDINGS)
|
||||||
{
|
{
|
||||||
|
@@ -42,7 +42,7 @@ public:
|
|||||||
virtual void visitSetSecSkill(SetSecSkill & pack) {}
|
virtual void visitSetSecSkill(SetSecSkill & pack) {}
|
||||||
virtual void visitHeroVisitCastle(HeroVisitCastle & pack) {}
|
virtual void visitHeroVisitCastle(HeroVisitCastle & pack) {}
|
||||||
virtual void visitChangeSpells(ChangeSpells & pack) {}
|
virtual void visitChangeSpells(ChangeSpells & pack) {}
|
||||||
virtual void visitSetTownSpells(SetTownSpells & pack) {}
|
virtual void visitSetResearchedSpells(SetResearchedSpells & pack) {}
|
||||||
virtual void visitSetMana(SetMana & pack) {}
|
virtual void visitSetMana(SetMana & pack) {}
|
||||||
virtual void visitSetMovePoints(SetMovePoints & pack) {}
|
virtual void visitSetMovePoints(SetMovePoints & pack) {}
|
||||||
virtual void visitFoWChange(FoWChange & pack) {}
|
virtual void visitFoWChange(FoWChange & pack) {}
|
||||||
|
@@ -162,9 +162,9 @@ void ChangeSpells::visitTyped(ICPackVisitor & visitor)
|
|||||||
visitor.visitChangeSpells(*this);
|
visitor.visitChangeSpells(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTownSpells::visitTyped(ICPackVisitor & visitor)
|
void SetResearchedSpells::visitTyped(ICPackVisitor & visitor)
|
||||||
{
|
{
|
||||||
visitor.visitSetTownSpells(*this);
|
visitor.visitSetResearchedSpells(*this);
|
||||||
}
|
}
|
||||||
void SetMana::visitTyped(ICPackVisitor & visitor)
|
void SetMana::visitTyped(ICPackVisitor & visitor)
|
||||||
{
|
{
|
||||||
@@ -939,12 +939,14 @@ void ChangeSpells::applyGs(CGameState *gs)
|
|||||||
hero->removeSpellFromSpellbook(sid);
|
hero->removeSpellFromSpellbook(sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTownSpells::applyGs(CGameState *gs)
|
void SetResearchedSpells::applyGs(CGameState *gs)
|
||||||
{
|
{
|
||||||
CGTownInstance *town = gs->getTown(tid);
|
CGTownInstance *town = gs->getTown(tid);
|
||||||
|
|
||||||
town->spells[level] = spells;
|
town->spells[level] = spells;
|
||||||
town->lastSpellResearchDay = gs->getDate(Date::DAY);
|
town->lastSpellResearchDay = gs->getDate(Date::DAY);
|
||||||
|
if(accepted)
|
||||||
|
town->spellResearchCounter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMana::applyGs(CGameState *gs)
|
void SetMana::applyGs(CGameState *gs)
|
||||||
|
@@ -288,7 +288,7 @@ struct DLL_LINKAGE ChangeSpells : public CPackForClient
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DLL_LINKAGE SetTownSpells : public CPackForClient
|
struct DLL_LINKAGE SetResearchedSpells : public CPackForClient
|
||||||
{
|
{
|
||||||
void applyGs(CGameState * gs) override;
|
void applyGs(CGameState * gs) override;
|
||||||
|
|
||||||
@@ -297,12 +297,14 @@ struct DLL_LINKAGE SetTownSpells : public CPackForClient
|
|||||||
ui8 level = 0;
|
ui8 level = 0;
|
||||||
ObjectInstanceID tid;
|
ObjectInstanceID tid;
|
||||||
std::vector<SpellID> spells;
|
std::vector<SpellID> spells;
|
||||||
|
bool accepted;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler & h)
|
template <typename Handler> void serialize(Handler & h)
|
||||||
{
|
{
|
||||||
h & level;
|
h & level;
|
||||||
h & tid;
|
h & tid;
|
||||||
h & spells;
|
h & spells;
|
||||||
|
h & accepted;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -309,12 +309,13 @@ struct DLL_LINKAGE RazeStructure : public BuildStructure
|
|||||||
struct DLL_LINKAGE SpellResearch : public CPackForServer
|
struct DLL_LINKAGE SpellResearch : public CPackForServer
|
||||||
{
|
{
|
||||||
SpellResearch() = default;
|
SpellResearch() = default;
|
||||||
SpellResearch(const ObjectInstanceID & TID, SpellID spellAtSlot)
|
SpellResearch(const ObjectInstanceID & TID, SpellID spellAtSlot, bool accepted)
|
||||||
: tid(TID), spellAtSlot(spellAtSlot)
|
: tid(TID), spellAtSlot(spellAtSlot)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ObjectInstanceID tid;
|
ObjectInstanceID tid;
|
||||||
SpellID spellAtSlot;
|
SpellID spellAtSlot;
|
||||||
|
bool accepted;
|
||||||
|
|
||||||
void visitTyped(ICPackVisitor & visitor) override;
|
void visitTyped(ICPackVisitor & visitor) override;
|
||||||
|
|
||||||
@@ -323,6 +324,7 @@ struct DLL_LINKAGE SpellResearch : public CPackForServer
|
|||||||
h & static_cast<CPackForServer &>(*this);
|
h & static_cast<CPackForServer &>(*this);
|
||||||
h & tid;
|
h & tid;
|
||||||
h & spellAtSlot;
|
h & spellAtSlot;
|
||||||
|
h & accepted;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -289,7 +289,7 @@ void registerTypes(Serializer &s)
|
|||||||
s.template registerType<LobbyForceSetPlayer>(239);
|
s.template registerType<LobbyForceSetPlayer>(239);
|
||||||
s.template registerType<LobbySetExtraOptions>(240);
|
s.template registerType<LobbySetExtraOptions>(240);
|
||||||
s.template registerType<SpellResearch>(241);
|
s.template registerType<SpellResearch>(241);
|
||||||
s.template registerType<SetTownSpells>(242);
|
s.template registerType<SetResearchedSpells>(242);
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@@ -1235,12 +1235,13 @@ void CGameHandler::changeSpells(const CGHeroInstance * hero, bool give, const st
|
|||||||
sendAndApply(&cs);
|
sendAndApply(&cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::setTownSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells)
|
void CGameHandler::setResearchedSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells, bool accepted)
|
||||||
{
|
{
|
||||||
SetTownSpells cs;
|
SetResearchedSpells cs;
|
||||||
cs.tid = town->id;
|
cs.tid = town->id;
|
||||||
cs.spells = spells;
|
cs.spells = spells;
|
||||||
cs.level = level;
|
cs.level = level;
|
||||||
|
cs.accepted = accepted;
|
||||||
sendAndApply(&cs);
|
sendAndApply(&cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2242,7 +2243,7 @@ bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot)
|
bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot, bool accepted)
|
||||||
{
|
{
|
||||||
CGTownInstance *t = gs->getTown(tid);
|
CGTownInstance *t = gs->getTown(tid);
|
||||||
|
|
||||||
@@ -2263,7 +2264,7 @@ bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot)
|
|||||||
|
|
||||||
auto costBase = TResources(getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE));
|
auto costBase = TResources(getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_BASE));
|
||||||
auto costPerLevel = TResources(getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL));
|
auto costPerLevel = TResources(getSettings().getValue(EGameSettings::TOWNS_SPELL_RESEARCH_COST_PER_LEVEL));
|
||||||
auto cost = costBase + costPerLevel * (level + 1);
|
auto cost = (costBase + costPerLevel * (level + 1)) * (t->spellResearchCounter + 1);
|
||||||
|
|
||||||
if(!getPlayerState(t->getOwner())->resources.canAfford(cost) && complain("Spell replacement cannot be afforded!"))
|
if(!getPlayerState(t->getOwner())->resources.canAfford(cost) && complain("Spell replacement cannot be afforded!"))
|
||||||
return false;
|
return false;
|
||||||
@@ -2276,7 +2277,7 @@ bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot)
|
|||||||
auto it = spells.begin() + t->spellsAtLevel(level, false);
|
auto it = spells.begin() + t->spellsAtLevel(level, false);
|
||||||
std::rotate(it, it + 1, spells.end()); // move to end
|
std::rotate(it, it + 1, spells.end()); // move to end
|
||||||
|
|
||||||
setTownSpells(t, level, spells);
|
setResearchedSpells(t, level, spells, accepted);
|
||||||
|
|
||||||
if(t->visitingHero)
|
if(t->visitingHero)
|
||||||
giveSpells(t, t->visitingHero);
|
giveSpells(t, t->visitingHero);
|
||||||
|
@@ -107,7 +107,7 @@ public:
|
|||||||
//from IGameCallback
|
//from IGameCallback
|
||||||
//do sth
|
//do sth
|
||||||
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override;
|
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override;
|
||||||
void setTownSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells) override;
|
void setResearchedSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells, bool accepted) override;
|
||||||
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override;
|
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override;
|
||||||
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
|
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
|
||||||
void giveExperience(const CGHeroInstance * hero, TExpType val) override;
|
void giveExperience(const CGHeroInstance * hero, TExpType val) override;
|
||||||
@@ -219,7 +219,7 @@ public:
|
|||||||
bool buildStructure(ObjectInstanceID tid, BuildingID bid, bool force=false);//force - for events: no cost, no checkings
|
bool buildStructure(ObjectInstanceID tid, BuildingID bid, bool force=false);//force - for events: no cost, no checkings
|
||||||
bool visitTownBuilding(ObjectInstanceID tid, BuildingID bid);
|
bool visitTownBuilding(ObjectInstanceID tid, BuildingID bid);
|
||||||
bool razeStructure(ObjectInstanceID tid, BuildingID bid);
|
bool razeStructure(ObjectInstanceID tid, BuildingID bid);
|
||||||
bool spellResearch(ObjectInstanceID tid, SpellID spellAtSlot);
|
bool spellResearch(ObjectInstanceID tid, SpellID spellAtSlot, bool accepted);
|
||||||
bool disbandCreature( ObjectInstanceID id, SlotID pos );
|
bool disbandCreature( ObjectInstanceID id, SlotID pos );
|
||||||
bool arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player);
|
bool arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player);
|
||||||
bool bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot);
|
bool bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot);
|
||||||
|
@@ -143,7 +143,7 @@ void ApplyGhNetPackVisitor::visitSpellResearch(SpellResearch & pack)
|
|||||||
gh.throwIfWrongOwner(&pack, pack.tid);
|
gh.throwIfWrongOwner(&pack, pack.tid);
|
||||||
gh.throwIfPlayerNotActive(&pack);
|
gh.throwIfPlayerNotActive(&pack);
|
||||||
|
|
||||||
result = gh.spellResearch(pack.tid, pack.spellAtSlot);
|
result = gh.spellResearch(pack.tid, pack.spellAtSlot, pack.accepted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyGhNetPackVisitor::visitVisitTownBuilding(VisitTownBuilding & pack)
|
void ApplyGhNetPackVisitor::visitVisitTownBuilding(VisitTownBuilding & pack)
|
||||||
|
@@ -44,7 +44,7 @@ public:
|
|||||||
void showInfoDialog(InfoWindow * iw) override {}
|
void showInfoDialog(InfoWindow * iw) override {}
|
||||||
|
|
||||||
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override {}
|
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override {}
|
||||||
void setTownSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells) override {}
|
void setResearchedSpells(const CGTownInstance * town, int level, const std::vector<SpellID> spells, bool accepted) override {}
|
||||||
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;}
|
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;}
|
||||||
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {}
|
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {}
|
||||||
void setOwner(const CGObjectInstance * objid, PlayerColor owner) override {}
|
void setOwner(const CGObjectInstance * objid, PlayerColor owner) override {}
|
||||||
|
Reference in New Issue
Block a user