1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-09 13:14:02 +02:00

Fixed Battle Creature Order

Fixed the messy creature order. It now follows correctly all creature ordering rules.
This commit is contained in:
Ewilhan 2019-05-16 14:41:02 +01:00
parent aee4bb7281
commit ab1c598d4e
3 changed files with 94 additions and 65 deletions

View File

@ -804,7 +804,6 @@ void BattleInfo::addUnit(uint32_t id, const JsonNode & data)
void BattleInfo::moveUnit(uint32_t id, BattleHex destination) void BattleInfo::moveUnit(uint32_t id, BattleHex destination)
{ {
auto sta = getStack(id); auto sta = getStack(id);
if(!sta) if(!sta)
{ {
logGlobal->error("Cannot find stack %d", id); logGlobal->error("Cannot find stack %d", id);
@ -1063,28 +1062,38 @@ bool CMP_stack::operator()(const battle::Unit * a, const battle::Unit * b)
int as = a->getInitiative(turn), bs = b->getInitiative(turn); int as = a->getInitiative(turn), bs = b->getInitiative(turn);
if(as != bs) if(as != bs)
return as > bs; return as > bs;
else if(as == bs)
{
if(a->unitSide() == b->unitSide())
return a->unitSlot() < b->unitSlot();
else else
return a->unitSlot() < b->unitSlot(); //FIXME: what about summoned stacks? return a->unitSide() == side ? false : true;
}
//FIXME: what about summoned stacks
} }
case 2: //fastest last, upper slot first case 2: //fastest last, upper slot first
//TODO: should be replaced with order of receiving morale!
case 3: //fastest last, upper slot first case 3: //fastest last, upper slot first
{ {
int as = a->getInitiative(turn), bs = b->getInitiative(turn); int as = a->getInitiative(turn), bs = b->getInitiative(turn);
if(as != bs) if(as != bs)
return as < bs; return as > bs;
else else if(as == bs)
{
if(a->unitSide() == b->unitSide())
return a->unitSlot() < b->unitSlot(); return a->unitSlot() < b->unitSlot();
else
return a->unitSide() == side ? false : true;
}
} }
default: default:
assert(0); assert(0);
return false; return false;
} }
} }
CMP_stack::CMP_stack(int Phase, int Turn) CMP_stack::CMP_stack(int Phase, int Turn, int Side)
{ {
phase = Phase; phase = Phase;
turn = Turn; turn = Turn;
side = Side;
} }

View File

@ -144,8 +144,9 @@ class DLL_LINKAGE CMP_stack
{ {
int phase; //rules of which phase will be used int phase; //rules of which phase will be used
int turn; int turn;
bool side;
public: public:
bool operator ()(const battle::Unit * a, const battle::Unit * b); bool operator ()(const battle::Unit * a, const battle::Unit * b);
CMP_stack(int Phase = 1, int Turn = 0); CMP_stack(int Phase = 1, int Turn = 0, int Side = BattleSide::ATTACKER);
}; };

View File

@ -353,57 +353,67 @@ battle::Units CBattleInfoCallback::battleAliveUnits(ui8 side) const
//T is battle::Unit descendant //T is battle::Unit descendant
template <typename T> template <typename T>
const T * takeOneUnit(std::vector<const T *> & all, const int turn, int8_t & lastMoved) const T * takeOneUnit(std::vector<const T*> & all, const int turn, int8_t & lastMoved, int phase)
{ {
const T * ret = nullptr; const T * retCreature = nullptr;
size_t i, //fastest stack size_t fastestIndex = 0;
j=0; //fastest stack of the other side
for(i = 0; i < all.size(); i++) for(int i = 0; i < all.size(); i++)
{
int32_t curUnitSpeed = -1;
int32_t retUnitSpeed = -1;
if(all[i]) if(all[i])
break; curUnitSpeed = all[i]->getInitiative(turn);
if(retCreature)
retUnitSpeed = retCreature->getInitiative(turn);
//no stacks left switch(phase)
if(i == all.size()) {
case 1: // Faster first, attacker priority, higher slot first
if(all[i] && (retCreature == nullptr || (curUnitSpeed > retUnitSpeed)))
{
retCreature = all[i];
fastestIndex = i;
}
else if(all[i] && (curUnitSpeed == retUnitSpeed))
{
if(lastMoved == -1 && turn <= 0 && all[i]->unitSide() == BattleSide::ATTACKER
&& !(retCreature->unitSide() == all[i]->unitSide() && retCreature->unitSlot() < all[i]->unitSlot())) // Turn 0 attacker priority
{
retCreature = all[i];
fastestIndex = i;
}
else if(lastMoved != -1 && all[i]->unitSide() != lastMoved
&& !(retCreature->unitSide() == all[i]->unitSide() && retCreature->unitSlot() < all[i]->unitSlot())) // Alternate equal speeds units
{
retCreature = all[i];
fastestIndex = i;
}
}
break;
case 2: // Slower first, higher slot first
case 3:
if(all[i] && (retCreature == nullptr || (curUnitSpeed < retUnitSpeed)))
{
retCreature = all[i];
fastestIndex = i;
}
else if(all[i] && curUnitSpeed == retUnitSpeed && lastMoved != -1 && all[i]->unitSide() != lastMoved
&& !(retCreature->unitSide() == all[i]->unitSide() && retCreature->unitSlot() < all[i]->unitSlot())) // Alternate equal speeds units
{
retCreature = all[i];
fastestIndex = i;
}
break;
default:
break;
}
}
if(!retCreature)
return nullptr; return nullptr;
all[fastestIndex] = nullptr;
const T * fastest = all[i], *other = nullptr; return retCreature;
int bestSpeed = fastest->getInitiative(turn);
if(fastest->unitSide() == lastMoved)
{
ret = fastest;
}
else
{
for(j = i + 1; j < all.size(); j++)
{
if(!all[j]) continue;
if(all[j]->unitSide() != lastMoved || all[j]->getInitiative(turn) != bestSpeed)
break;
}
if(j >= all.size())
{
ret = fastest;
}
else
{
other = all[j];
if(other->getInitiative(turn) != bestSpeed)
ret = fastest;
else
ret = other;
}
}
assert(ret);
if(ret == fastest)
all[i] = nullptr;
else
all[j] = nullptr;
lastMoved = ret->unitSide();
return ret;
} }
void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & out, const size_t maxUnits, const int maxTurns, const int turn, int8_t lastMoved) const void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & out, const size_t maxUnits, const int maxTurns, const int turn, int8_t lastMoved) const
@ -483,27 +493,36 @@ void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & out, c
phase[p].push_back(one); phase[p].push_back(one);
} }
boost::sort(phase[0], CMP_stack(0, actualTurn)); boost::sort(phase[0], CMP_stack(0, actualTurn, lastMoved));
std::copy(phase[0].begin(), phase[0].end(), std::back_inserter(out.back())); std::copy(phase[0].begin(), phase[0].end(), std::back_inserter(out.back()));
if(outputFull()) if(outputFull())
return; return;
for(int i = 1; i < 4; i++) for(int i = 1; i < 4; i++)
boost::sort(phase[i], CMP_stack(i, actualTurn)); boost::sort(phase[i], CMP_stack(i, actualTurn, lastMoved));
if(lastMoved < 0)
lastMoved = BattleSide::ATTACKER;
int pi = 1; int pi = 1;
while(!outputFull() && pi < 4) while(!outputFull() && pi < 4)
{ {
auto current = takeOneUnit(phase[pi], actualTurn, lastMoved); const battle::Unit * current = nullptr;
if(phase[pi].empty())
pi++;
else
{
current = takeOneUnit(phase[pi], actualTurn, lastMoved, pi);
if(!current) if(!current)
pi++; pi++;
else else
{
out.back().push_back(current); out.back().push_back(current);
lastMoved = current->unitSide();
} }
}
}
if (lastMoved < 0)
lastMoved = BattleSide::ATTACKER;
if(!outputFull() && (maxTurns == 0 || out.size() < maxTurns)) if(!outputFull() && (maxTurns == 0 || out.size() < maxTurns))
battleGetTurnOrder(out, maxUnits, maxTurns, actualTurn + 1, lastMoved); battleGetTurnOrder(out, maxUnits, maxTurns, actualTurn + 1, lastMoved);