mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-03 13:01:33 +02:00
Fixed Duel mode. Integrated some changes from programmingChallenge branch - it's possible to define duel parameters using JSON.
This commit is contained in:
parent
9327823355
commit
5981ad15d4
@ -480,7 +480,11 @@ void CBattleResultWindow::bExitf()
|
||||
{
|
||||
if(LOCPLINT->cb->getStartInfo()->mode == StartInfo::DUEL)
|
||||
{
|
||||
std::exit(0);
|
||||
SDL_Event ev;
|
||||
ev.type = SDL_QUIT;
|
||||
ev.user.code = 0;
|
||||
SDL_PushEvent(&ev);
|
||||
return;
|
||||
}
|
||||
|
||||
CPlayerInterface * intTmp = owner->curInt;
|
||||
|
@ -393,9 +393,11 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
|
||||
if(si->mode == StartInfo::DUEL)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
|
||||
CPlayerInterface *p = new CPlayerInterface(-1);
|
||||
p->observerInDuelMode = true;
|
||||
battleints[254] = playerint[254] = p;
|
||||
privilagedBattleEventReceivers.push_back(p);
|
||||
GH.curInt = p;
|
||||
p->init(new CCallback(gs, -1, this));
|
||||
battleStarted(gs->curB);
|
||||
|
@ -848,56 +848,8 @@ void CGameState::init(StartInfo * si)
|
||||
}
|
||||
break;
|
||||
case StartInfo::DUEL:
|
||||
{
|
||||
DuelParameters dp;
|
||||
try
|
||||
{
|
||||
CLoadFile lf(scenarioOps->mapname);
|
||||
lf >> dp;
|
||||
}
|
||||
catch(...)
|
||||
{}
|
||||
|
||||
|
||||
const CArmedInstance *armies[2] = {0};
|
||||
const CGHeroInstance *heroes[2] = {0};
|
||||
CGTownInstance *town = NULL;
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
CArmedInstance *obj = NULL;
|
||||
if(dp.sides[i].heroId >= 0)
|
||||
{
|
||||
CGHeroInstance *h = new CGHeroInstance();
|
||||
armies[i] = heroes[i] = h;
|
||||
obj = h;
|
||||
h->subID = dp.sides[i].heroId;
|
||||
h->initHero(h->subID);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGCreature *c = new CGCreature();
|
||||
armies[i] = obj = c;
|
||||
c->subID = 34;
|
||||
|
||||
}
|
||||
|
||||
obj->initObj();
|
||||
obj->setOwner(i);
|
||||
|
||||
for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++)
|
||||
{
|
||||
int cre = dp.sides[i].stacks[j].type, count = dp.sides[i].stacks[j].count;
|
||||
if(count || obj->hasStackAtSlot(j))
|
||||
obj->setCreature(j, cre, count);
|
||||
}
|
||||
}
|
||||
|
||||
curB = BattleInfo::setupBattle(int3(), dp.bfieldType, dp.terType, armies, heroes, false, town);
|
||||
curB->localInit();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
initDuel();
|
||||
return;
|
||||
default:
|
||||
tlog1 << "Wrong mode: " << (int)scenarioOps->mode << std::endl;
|
||||
return;
|
||||
@ -1527,6 +1479,108 @@ void CGameState::init(StartInfo * si)
|
||||
}
|
||||
}
|
||||
|
||||
void CGameState::initDuel()
|
||||
{
|
||||
DuelParameters dp;
|
||||
try //CLoadFile likes throwing
|
||||
{
|
||||
if(boost::algorithm::ends_with(scenarioOps->mapname, ".json"))
|
||||
{
|
||||
tlog0 << "Loading duel settings from JSON file: " << scenarioOps->mapname << std::endl;
|
||||
dp = DuelParameters::fromJSON(scenarioOps->mapname);
|
||||
tlog0 << "JSON file has been successfully read!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
CLoadFile lf(scenarioOps->mapname);
|
||||
lf >> dp;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
tlog1 << "Cannot load duel settings from " << scenarioOps->mapname << std::endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
const CArmedInstance *armies[2] = {0};
|
||||
const CGHeroInstance *heroes[2] = {0};
|
||||
CGTownInstance *town = NULL;
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
CArmedInstance *obj = NULL;
|
||||
if(dp.sides[i].heroId >= 0)
|
||||
{
|
||||
const DuelParameters::SideSettings &ss = dp.sides[i];
|
||||
CGHeroInstance *h = new CGHeroInstance();
|
||||
armies[i] = heroes[i] = h;
|
||||
obj = h;
|
||||
h->subID = ss.heroId;
|
||||
for(int i = 0; i < ss.heroPrimSkills.size(); i++)
|
||||
h->pushPrimSkill(i, ss.heroPrimSkills[i]);
|
||||
|
||||
if(ss.spells.size())
|
||||
{
|
||||
h->putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
|
||||
boost::copy(ss.spells, std::inserter(h->spells, h->spells.begin()));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(auto &parka, ss.artifacts)
|
||||
{
|
||||
h->putArtifact(parka.first, parka.second);
|
||||
}
|
||||
|
||||
typedef const std::pair<si32, si8> &TSecSKill;
|
||||
BOOST_FOREACH(TSecSKill secSkill, ss.heroSecSkills)
|
||||
h->setSecSkillLevel((CGHeroInstance::SecondarySkill)secSkill.first, secSkill.second, 1);
|
||||
|
||||
h->initHero(h->subID);
|
||||
obj->initObj();
|
||||
}
|
||||
else
|
||||
{
|
||||
CGCreature *c = new CGCreature();
|
||||
armies[i] = obj = c;
|
||||
//c->subID = 34;
|
||||
}
|
||||
|
||||
obj->setOwner(i);
|
||||
|
||||
for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++)
|
||||
{
|
||||
TCreature cre = dp.sides[i].stacks[j].type;
|
||||
TQuantity count = dp.sides[i].stacks[j].count;
|
||||
if(count || obj->hasStackAtSlot(j))
|
||||
obj->setCreature(j, cre, count);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const DuelParameters::CusomCreature &cc, dp.creatures)
|
||||
{
|
||||
CCreature *c = VLC->creh->creatures[cc.id];
|
||||
if(cc.attack >= 0)
|
||||
c->getBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK))->val = cc.attack;
|
||||
if(cc.defense >= 0)
|
||||
c->getBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))->val = cc.defense;
|
||||
if(cc.speed >= 0)
|
||||
c->getBonus(Selector::type(Bonus::STACKS_SPEED))->val = cc.speed;
|
||||
if(cc.HP >= 0)
|
||||
c->getBonus(Selector::type(Bonus::STACK_HEALTH))->val = cc.HP;
|
||||
if(cc.dmg >= 0)
|
||||
{
|
||||
c->getBonus(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1))->val = cc.dmg;
|
||||
c->getBonus(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2))->val = cc.dmg;
|
||||
}
|
||||
if(cc.shoots >= 0)
|
||||
c->getBonus(Selector::type(Bonus::SHOTS))->val = cc.shoots;
|
||||
}
|
||||
}
|
||||
|
||||
curB = BattleInfo::setupBattle(int3(), dp.bfieldType, dp.terType, armies, heroes, false, town);
|
||||
curB->obstacles = dp.obstacles;
|
||||
curB->localInit();
|
||||
return;
|
||||
}
|
||||
|
||||
int CGameState::battleGetBattlefieldType(int3 tile) const
|
||||
{
|
||||
if(tile==int3() && curB)
|
||||
@ -2723,6 +2777,88 @@ DuelParameters::DuelParameters()
|
||||
bfieldType = 15;
|
||||
}
|
||||
|
||||
DuelParameters DuelParameters::fromJSON(const std::string &fname)
|
||||
{
|
||||
DuelParameters ret;
|
||||
|
||||
const JsonNode duelData(fname);
|
||||
ret.terType = duelData["terType"].Float();
|
||||
ret.bfieldType = duelData["bfieldType"].Float();
|
||||
BOOST_FOREACH(const JsonNode &n, duelData["sides"].Vector())
|
||||
{
|
||||
SideSettings &ss = ret.sides[(int)n["side"].Float()];
|
||||
int i = 0;
|
||||
BOOST_FOREACH(const JsonNode &stackNode, n["army"].Vector())
|
||||
{
|
||||
ss.stacks[i].type = stackNode.Vector()[0].Float();
|
||||
ss.stacks[i].count = stackNode.Vector()[1].Float();
|
||||
i++;
|
||||
}
|
||||
|
||||
if(n["heroid"].getType() == JsonNode::DATA_FLOAT)
|
||||
ss.heroId = n["heroid"].Float();
|
||||
else
|
||||
ss.heroId = -1;
|
||||
|
||||
BOOST_FOREACH(const JsonNode &n, n["heroPrimSkills"].Vector())
|
||||
ss.heroPrimSkills.push_back(n.Float());
|
||||
|
||||
BOOST_FOREACH(const JsonNode &skillNode, n["heroSecSkills"].Vector())
|
||||
{
|
||||
std::pair<si32, si8> secSkill;
|
||||
secSkill.first = skillNode.Vector()[0].Float();
|
||||
secSkill.second = skillNode.Vector()[1].Float();
|
||||
ss.heroSecSkills.push_back(secSkill);
|
||||
}
|
||||
|
||||
assert(ss.heroPrimSkills.empty() || ss.heroPrimSkills.size() == GameConstants::PRIMARY_SKILLS);
|
||||
|
||||
if(ss.heroId != -1)
|
||||
BOOST_FOREACH(const JsonNode &spell, n["spells"].Vector())
|
||||
ss.spells.insert(spell.Float());
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const JsonNode &n, duelData["obstacles"].Vector())
|
||||
{
|
||||
auto oi = make_shared<CObstacleInstance>();
|
||||
if(n.getType() == JsonNode::DATA_VECTOR)
|
||||
{
|
||||
oi->ID = n.Vector()[0].Float();
|
||||
oi->pos = n.Vector()[1].Float();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(n.getType() == JsonNode::DATA_FLOAT);
|
||||
oi->ID = 21;
|
||||
oi->pos = n.Float();
|
||||
}
|
||||
oi->uniqueID = ret.obstacles.size();
|
||||
ret.obstacles.push_back(oi);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const JsonNode &n, duelData["creatures"].Vector())
|
||||
{
|
||||
CusomCreature cc;
|
||||
cc.id = n["id"].Float();
|
||||
|
||||
#define retreive(name) \
|
||||
if(n[ #name ].getType() == JsonNode::DATA_FLOAT)\
|
||||
cc.name = n[ #name ].Float(); \
|
||||
else \
|
||||
cc.name = -1;
|
||||
|
||||
retreive(attack);
|
||||
retreive(defense);
|
||||
retreive(HP);
|
||||
retreive(dmg);
|
||||
retreive(shoots);
|
||||
retreive(speed);
|
||||
ret.creatures.push_back(cc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TeamState::TeamState()
|
||||
{
|
||||
setNodeType(TEAM);
|
||||
|
@ -284,12 +284,12 @@ struct DLL_LINKAGE CPathsInfo
|
||||
~CPathsInfo();
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE DuelParameters
|
||||
struct DLL_EXPORT DuelParameters
|
||||
{
|
||||
si32 terType, bfieldType;
|
||||
struct SideSettings
|
||||
struct DLL_EXPORT SideSettings
|
||||
{
|
||||
struct StackSettings
|
||||
struct DLL_EXPORT StackSettings
|
||||
{
|
||||
si32 type;
|
||||
si32 count;
|
||||
@ -300,23 +300,46 @@ struct DLL_LINKAGE DuelParameters
|
||||
|
||||
StackSettings();
|
||||
StackSettings(si32 Type, si32 Count);
|
||||
};
|
||||
StackSettings stacks[GameConstants::ARMY_SIZE];
|
||||
} stacks[GameConstants::ARMY_SIZE];
|
||||
|
||||
si32 heroId; //-1 if none
|
||||
std::vector<si32> heroPrimSkills; //may be empty
|
||||
std::map<si32, CArtifactInstance*> artifacts;
|
||||
std::vector<std::pair<si32, si8> > heroSecSkills; //may be empty; pairs <id, level>, level [0-3]
|
||||
std::set<si32> spells;
|
||||
|
||||
SideSettings();
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & stacks & heroId & spells;
|
||||
h & stacks & heroId & heroPrimSkills & artifacts & heroSecSkills & spells;
|
||||
}
|
||||
} sides[2];
|
||||
|
||||
std::vector<shared_ptr<CObstacleInstance> > obstacles;
|
||||
|
||||
static DuelParameters fromJSON(const std::string &fname);
|
||||
|
||||
struct CusomCreature
|
||||
{
|
||||
int id;
|
||||
int attack, defense, dmg, HP, speed, shoots;
|
||||
|
||||
CusomCreature()
|
||||
{
|
||||
id = attack = defense = dmg = HP = speed = shoots = -1;
|
||||
}
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & id & attack & defense & dmg & HP & speed & shoots;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<CusomCreature> creatures;
|
||||
|
||||
DuelParameters();
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & terType & bfieldType & sides;
|
||||
h & terType & bfieldType & sides & obstacles & creatures;
|
||||
}
|
||||
};
|
||||
|
||||
@ -387,6 +410,8 @@ public:
|
||||
boost::shared_mutex *mx;
|
||||
|
||||
void init(StartInfo * si);
|
||||
|
||||
void initDuel();
|
||||
void loadTownDInfos();
|
||||
void randomizeObject(CGObjectInstance *cur);
|
||||
std::pair<int,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
|
||||
|
@ -56,6 +56,8 @@ si8 CBattleInfoCallback::battleCanTeleportTo(const CStack * stack, BattleHex des
|
||||
|
||||
std::vector<int> CBattleInfoCallback::battleGetDistances(const CStack * stack, BattleHex hex /*= BattleHex::INVALID*/, BattleHex * predecessors /*= NULL*/)
|
||||
{
|
||||
// FIXME - This method is broken, hex argument is not used. However AI depends on that wrong behaviour.
|
||||
|
||||
if(!hex.isValid())
|
||||
hex = stack->position;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user