diff --git a/client/CBitmapHandler.cpp b/client/CBitmapHandler.cpp index 42c29f604..c7d774689 100644 --- a/client/CBitmapHandler.cpp +++ b/client/CBitmapHandler.cpp @@ -159,7 +159,7 @@ SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey) if (!(bitmap = loadBitmapFromDir("DATA/", fname, setKey)) && !(bitmap = loadBitmapFromDir("SPRITES/", fname, setKey))) - tlog0<<"Error: Failed to find file "<= GameConstants::ARMY_SIZE) + { + tlog3 << "Warning: " << army.name << " has stack in slot " << slot.first << std::endl; + continue; + } + new CAnimImage("CPRSMALL", slot.second.type->idNumber + 2, 0, slotsPos[slot.first].x, slotsPos[slot.first].y); std::string subtitle; diff --git a/config/battleStartpos.json b/config/battleStartpos.json index c193c8f71..255a6ec6e 100644 --- a/config/battleStartpos.json +++ b/config/battleStartpos.json @@ -71,11 +71,11 @@ "levels": [ [ 15 ], [ 15, 185 ], - [ 15, 185, 171 ], - [ 15, 185, 171, 1 ], - [ 15, 185, 171, 1, 100 ], - [ 15, 185, 171, 1, 100, 86 ], - [ 15, 185, 171, 1, 100, 86, 8 ] + [ 15, 185, 172 ], + [ 15, 185, 172, 2 ], + [ 15, 185, 172, 2, 100 ], + [ 15, 185, 172, 2, 100, 86 ], + [ 15, 185, 172, 2, 100, 86, 8 ] ] } ], diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 032a92e91..98f53f8af 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -911,17 +911,17 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp //reading battleStartpos - add creatures AFTER random obstacles are generated //TODO: parse once to some structure - std::vector< std::vector > attackerLoose, defenderLoose, attackerTight, defenderTight, attackerCreBank, defenderCreBank; + std::vector< std::vector > looseFormations[2], tightFormations[2], creBankFormations[2]; std::vector commanderField, commanderBank; const JsonNode config(ResourceID("config/battleStartpos.json")); const JsonVector &positions = config["battle_positions"].Vector(); - CGH::readBattlePositions(positions[0]["levels"], attackerLoose); - CGH::readBattlePositions(positions[1]["levels"], defenderLoose); - CGH::readBattlePositions(positions[2]["levels"], attackerTight); - CGH::readBattlePositions(positions[3]["levels"], defenderTight); - CGH::readBattlePositions(positions[4]["levels"], attackerCreBank); - CGH::readBattlePositions(positions[5]["levels"], defenderCreBank); + CGH::readBattlePositions(positions[0]["levels"], looseFormations[0]); + CGH::readBattlePositions(positions[1]["levels"], looseFormations[1]); + CGH::readBattlePositions(positions[2]["levels"], tightFormations[0]); + CGH::readBattlePositions(positions[3]["levels"], tightFormations[1]); + CGH::readBattlePositions(positions[4]["levels"], creBankFormations[0]); + CGH::readBattlePositions(positions[5]["levels"], creBankFormations[1]); BOOST_FOREACH (auto position, config["commanderPositions"]["field"].Vector()) { @@ -957,52 +957,31 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp //war machines added //battleStartpos read - int k = 0; //stack serial - for(TSlots::const_iterator i = armies[0]->Slots().begin(); i!=armies[0]->Slots().end(); i++, k++) + for(int side = 0; side < 2; side++) { - int pos; - if(creatureBank) - pos = attackerCreBank[armies[0]->stacksCount()-1][k]; - else if(armies[0]->formation) - pos = attackerTight[armies[0]->stacksCount()-1][k]; - else - pos = attackerLoose[armies[0]->stacksCount()-1][k]; + int formationNo = armies[side]->stacksCount() - 1; + vstd::abetween(formationNo, 0, GameConstants::ARMY_SIZE - 1); - CStack * stack = curB->generateNewStack(*i->second, true, i->first, pos); - stacks.push_back(stack); + int k = 0; //stack serial + for(TSlots::const_iterator i = armies[side]->Slots().begin(); i != armies[side]->Slots().end(); i++, k++) + { + std::vector *formationVector = nullptr; + if(creatureBank) + formationVector = &creBankFormations[side][formationNo]; + else if(armies[side]->formation) + formationVector = &tightFormations[side][formationNo]; + else + formationVector = &looseFormations[side][formationNo]; + + BattleHex pos = (k < formationVector->size() ? formationVector->at(k) : 0); + if(creatureBank && i->second->type->isDoubleWide()) + pos += side ? BattleHex::LEFT : BattleHex::RIGHT; + + CStack * stack = curB->generateNewStack(*i->second, !side, i->first, pos); + stacks.push_back(stack); + } } - k = 0; - for(TSlots::const_iterator i = armies[1]->Slots().begin(); i!=armies[1]->Slots().end(); i++, k++) - { - int pos; - if(creatureBank) - pos = defenderCreBank[armies[1]->stacksCount()-1][k]; - else if(armies[1]->formation) - pos = defenderTight[armies[1]->stacksCount()-1][k]; - else - pos = defenderLoose[armies[1]->stacksCount()-1][k]; - - CStack * stack = curB->generateNewStack(*i->second, false, i->first, pos); - stacks.push_back(stack); - } - -// //shifting positions of two-hex creatures -// for(unsigned g=0; gdoubleWide() && stacks[g]->attackerOwned) -// { -// stacks[g]->position += BattleHex::RIGHT; -// } -// else if(stacks[g]->doubleWide() && !stacks[g]->attackerOwned) -// { -// if (stacks[g]->position.getX() > 1) -// stacks[g]->position += BattleHex::LEFT; -// } -// } - - //adding commanders for (int i = 0; i < 2; ++i) { diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 0edfd618e..2b5efd20c 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -348,7 +348,7 @@ bool CBattleInfoEssentials::battleCanSurrender(int player) const { RETURN_IF_NOT_BATTLE(false); //conditions like for fleeing + enemy must have a hero - return battleCanFlee(player) && battleGetFightingHero(!playerToSide(player)); + return battleCanFlee(player) && battleHasHero(!playerToSide(player)); } bool CBattleInfoEssentials::battleHasHero(ui8 side) const diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index 419de7a76..9f71ca78b 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -322,6 +322,7 @@ CArmedInstance * CCreatureSet::castToArmyObj() void CCreatureSet::putStack(TSlot slot, CStackInstance *stack) { + assert(slot < GameConstants::ARMY_SIZE); assert(!hasStackAtSlot(slot)); stacks[slot] = stack; stack->setArmyObj(castToArmyObj()); diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 1c1970bdc..0d2d0420f 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -185,6 +185,12 @@ struct StackLocation army = const_cast(Army); //we are allowed here to const cast -> change will go through one of our packages... do not abuse! slot = Slot; } + + bool validSlot() const + { + return slot >= 0 && slot < GameConstants::ARMY_SIZE; + } + DLL_LINKAGE const CStackInstance *getStack(); template void serialize(Handler &h, const int version) { diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 4f17fbe1b..be4db55d8 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2299,6 +2299,11 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, *s2 = static_cast(gs->map->objects[id2].get()); const CCreatureSet &S1 = *s1, &S2 = *s2; StackLocation sl1(s1, p1), sl2(s2, p2); + if(!sl1.validSlot() || !sl2.validSlot()) + { + complain("Invalid slot accessed!"); + return false; + } if(!isAllowedExchange(id1,id2)) { @@ -5616,6 +5621,9 @@ bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, T if(sl.army->hasStackAtSlot(sl.slot)) COMPLAIN_RET("Slot is already taken!"); + if(!sl.validSlot()) + COMPLAIN_RET("Cannot insert stack to that slot!"); + InsertNewStack ins; ins.sl = sl; ins.stack = CStackBasicDescriptor(c, count); @@ -5723,6 +5731,9 @@ bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst, if(dst.army->hasStackAtSlot(dst.slot) && dst.army->getCreature(dst.slot) != src.army->getCreature(src.slot)) COMPLAIN_RET("Cannot move: stack of different type at destination pos!"); + if(!dst.validSlot()) + COMPLAIN_RET("Cannot move stack to that slot!"); + if(count == -1) { count = src.army->getStackCount(src.slot); @@ -5733,7 +5744,7 @@ bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst, && src.army->Slots().size() == 1 //from the last stack && src.army->needsLastStack()) //that must be left { - COMPLAIN_RET("Cannot move away the alst creature!"); + COMPLAIN_RET("Cannot move away the last creature!"); } RebalanceStacks rs;