mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-10 09:50:17 +02:00
ecaa9f5d0b
* Made most Handlers derived from CHandlerBase and moved service API there. * Declared existing Entity APIs. * Added basic script context caching * Started Lua script module * Started Lua spell effect API * Started script state persistence * Started battle info callback binding * CommitPackage removed * Extracted spells::Caster to own header; Expanded Spell API. * implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C * !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented * Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key) * Re-enabled VERM macros. * !?GM0 added * !?TM implemented * Added !!MF:N * Started !?OB, !!BM, !!HE, !!OW, !!UN * Added basic support of w-variables * Added support for ERM indirect variables * Made !?FU regular trigger * !!re (ERA loop receiver) implemented * Fixed ERM receivers with zero args.
141 lines
3.9 KiB
C++
141 lines
3.9 KiB
C++
/*
|
|
* CArmedInstance.cpp, part of VCMI engine
|
|
*
|
|
* Authors: listed in file AUTHORS in main folder
|
|
*
|
|
* License: GNU General Public License v2.0 or later
|
|
* Full text of license available in license.txt file, in main folder
|
|
*
|
|
*/
|
|
|
|
#include "StdInc.h"
|
|
#include "CArmedInstance.h"
|
|
|
|
#include "../CTownHandler.h"
|
|
#include "../CCreatureHandler.h"
|
|
#include "../CGeneralTextHandler.h"
|
|
#include "../CGameState.h"
|
|
#include "../CPlayerState.h"
|
|
|
|
void CArmedInstance::randomizeArmy(int type)
|
|
{
|
|
for (auto & elem : stacks)
|
|
{
|
|
int & randID = elem.second->idRand;
|
|
if(randID >= 0)
|
|
{
|
|
int level = randID / 2;
|
|
bool upgrade = randID % 2;
|
|
elem.second->setType((*VLC->townh)[type]->town->creatures[level][upgrade]);
|
|
|
|
randID = -1;
|
|
}
|
|
assert(elem.second->valid(false));
|
|
assert(elem.second->armyObj == this);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
|
|
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(Bonus::NONEVIL_ALIGNMENT_MIX);
|
|
|
|
CArmedInstance::CArmedInstance()
|
|
:nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector)
|
|
{
|
|
battle = nullptr;
|
|
}
|
|
|
|
void CArmedInstance::updateMoraleBonusFromArmy()
|
|
{
|
|
if(!validTypes(false)) //object not randomized, don't bother
|
|
return;
|
|
|
|
auto b = getExportedBonusList().getFirst(Selector::sourceType()(Bonus::ARMY).And(Selector::type()(Bonus::MORALE)));
|
|
if(!b)
|
|
{
|
|
b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
|
|
addNewBonus(b);
|
|
}
|
|
|
|
//number of alignments and presence of undead
|
|
std::set<TFaction> factions;
|
|
bool hasUndead = false;
|
|
|
|
const std::string undeadCacheKey = "type_UNDEAD";
|
|
static const CSelector undeadSelector = Selector::type()(Bonus::UNDEAD);
|
|
|
|
for(auto slot : Slots())
|
|
{
|
|
const CStackInstance * inst = slot.second;
|
|
const CCreature * creature = VLC->creh->objects[inst->getCreatureID()];
|
|
|
|
factions.insert(creature->faction);
|
|
// Check for undead flag instead of faction (undead mummies are neutral)
|
|
hasUndead |= inst->hasBonus(undeadSelector, undeadCacheKey);
|
|
}
|
|
|
|
size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account
|
|
|
|
if (nonEvilAlignmentMix.getHasBonus())
|
|
{
|
|
size_t mixableFactions = 0;
|
|
|
|
for(TFaction f : factions)
|
|
{
|
|
if ((*VLC->townh)[f]->alignment != EAlignment::EVIL)
|
|
mixableFactions++;
|
|
}
|
|
if (mixableFactions > 0)
|
|
factionsInArmy -= mixableFactions - 1;
|
|
}
|
|
|
|
if(factionsInArmy == 1)
|
|
{
|
|
b->val = +1;
|
|
b->description = VLC->generaltexth->arraytxt[115]; //All troops of one alignment +1
|
|
b->description = b->description.substr(0, b->description.size()-3);//trim "+1"
|
|
}
|
|
else if (!factions.empty()) // no bonus from empty garrison
|
|
{
|
|
b->val = 2 - (si32)factionsInArmy;
|
|
b->description = boost::str(boost::format(VLC->generaltexth->arraytxt[114]) % factionsInArmy % b->val); //Troops of %d alignments %d
|
|
b->description = b->description.substr(0, b->description.size()-2);//trim value
|
|
}
|
|
boost::algorithm::trim(b->description);
|
|
CBonusSystemNode::treeHasChanged();
|
|
|
|
//-1 modifier for any Undead unit in army
|
|
const ui8 UNDEAD_MODIFIER_ID = -2;
|
|
auto undeadModifier = getExportedBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
|
|
if(hasUndead)
|
|
{
|
|
if(!undeadModifier)
|
|
{
|
|
undeadModifier = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]);
|
|
undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value
|
|
addNewBonus(undeadModifier);
|
|
}
|
|
}
|
|
else if(undeadModifier)
|
|
removeBonus(undeadModifier);
|
|
|
|
}
|
|
|
|
void CArmedInstance::armyChanged()
|
|
{
|
|
updateMoraleBonusFromArmy();
|
|
}
|
|
|
|
CBonusSystemNode * CArmedInstance::whereShouldBeAttached(CGameState *gs)
|
|
{
|
|
if(tempOwner < PlayerColor::PLAYER_LIMIT)
|
|
return gs->getPlayerState(tempOwner);
|
|
else
|
|
return &gs->globalEffects;
|
|
}
|
|
|
|
CBonusSystemNode * CArmedInstance::whatShouldBeAttached()
|
|
{
|
|
return this;
|
|
}
|