mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #2216 from vcmi/water_prison_tavern
Water Prison & Tavern
This commit is contained in:
commit
c52b5d3bd0
@ -228,7 +228,7 @@ public:
|
||||
void giveHeroBonus(GiveBonus * bonus) override {};
|
||||
void setMovePoints(SetMovePoints * smp) override {};
|
||||
void setManaPoints(ObjectInstanceID hid, int val) override {};
|
||||
void giveHero(ObjectInstanceID id, PlayerColor player) override {};
|
||||
void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override {};
|
||||
void changeObjPos(ObjectInstanceID objid, int3 newPos) override {};
|
||||
void sendAndApply(CPackForClient * pack) override {};
|
||||
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {};
|
||||
|
@ -130,7 +130,7 @@ public:
|
||||
virtual void giveHeroBonus(GiveBonus * bonus)=0;
|
||||
virtual void setMovePoints(SetMovePoints * smp)=0;
|
||||
virtual void setManaPoints(ObjectInstanceID hid, int val)=0;
|
||||
virtual void giveHero(ObjectInstanceID id, PlayerColor player)=0;
|
||||
virtual void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) = 0;
|
||||
virtual void changeObjPos(ObjectInstanceID objid, int3 newPos)=0;
|
||||
virtual void sendAndApply(CPackForClient * pack) = 0;
|
||||
virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map
|
||||
|
@ -690,6 +690,7 @@ struct DLL_LINKAGE HeroRecruited : public CPackForClient
|
||||
|
||||
si32 hid = -1; //subID of hero
|
||||
ObjectInstanceID tid;
|
||||
ObjectInstanceID boatId;
|
||||
int3 tile;
|
||||
PlayerColor player;
|
||||
|
||||
@ -699,6 +700,7 @@ struct DLL_LINKAGE HeroRecruited : public CPackForClient
|
||||
{
|
||||
h & hid;
|
||||
h & tid;
|
||||
h & boatId;
|
||||
h & tile;
|
||||
h & player;
|
||||
}
|
||||
@ -709,6 +711,7 @@ struct DLL_LINKAGE GiveHero : public CPackForClient
|
||||
void applyGs(CGameState * gs) const;
|
||||
|
||||
ObjectInstanceID id; //object id
|
||||
ObjectInstanceID boatId;
|
||||
PlayerColor player;
|
||||
|
||||
virtual void visitTyped(ICPackVisitor & visitor) override;
|
||||
@ -716,6 +719,7 @@ struct DLL_LINKAGE GiveHero : public CPackForClient
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & id;
|
||||
h & boatId;
|
||||
h & player;
|
||||
}
|
||||
};
|
||||
|
@ -1402,14 +1402,31 @@ void HeroRecruited::applyGs(CGameState * gs) const
|
||||
CGTownInstance *t = gs->getTown(tid);
|
||||
PlayerState *p = gs->getPlayerState(player);
|
||||
|
||||
assert(!h->boat);
|
||||
if (boatId >= 0)
|
||||
{
|
||||
CGObjectInstance *obj = gs->getObjInstance(boatId);
|
||||
auto * boat = dynamic_cast<CGBoat *>(obj);
|
||||
if (boat)
|
||||
{
|
||||
h->boat = boat;
|
||||
h->attachTo(*boat);
|
||||
boat->hero = h;
|
||||
}
|
||||
}
|
||||
|
||||
h->setOwner(player);
|
||||
h->pos = tile;
|
||||
bool fresh = !h->isInitialized();
|
||||
if(fresh)
|
||||
{ // this is a fresh hero who hasn't appeared yet
|
||||
h->movement = h->maxMovePoints(true);
|
||||
if (boatId >= 0) //Hero spawns on water
|
||||
{
|
||||
h->movement = h->maxMovePoints(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
h->movement = h->maxMovePoints(true);
|
||||
}
|
||||
}
|
||||
|
||||
gs->hpool.heroesPool.erase(hid);
|
||||
@ -1440,6 +1457,18 @@ void GiveHero::applyGs(CGameState * gs) const
|
||||
{
|
||||
CGHeroInstance *h = gs->getHero(id);
|
||||
|
||||
if (boatId >= 0)
|
||||
{
|
||||
CGObjectInstance *obj = gs->getObjInstance(boatId);
|
||||
auto * boat = dynamic_cast<CGBoat *>(obj);
|
||||
if (boat)
|
||||
{
|
||||
h->boat = boat;
|
||||
h->attachTo(*boat);
|
||||
boat->hero = h;
|
||||
}
|
||||
}
|
||||
|
||||
//bonus system
|
||||
h->detachFrom(gs->globalEffects);
|
||||
h->attachTo(*gs->getPlayerState(player));
|
||||
@ -1468,7 +1497,7 @@ void NewObject::applyGs(CGameState *gs)
|
||||
testObject.pos = pos;
|
||||
testObject.appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(ETerrainId::WATER).front();
|
||||
|
||||
[[maybe_unused]] const int3 previousXAxisTile = int3(pos.x - 1, pos.y, pos.z);
|
||||
[[maybe_unused]] const int3 previousXAxisTile = CGBoat::translatePos(pos, true);
|
||||
assert(gs->isInTheMap(previousXAxisTile) && (testObject.visitablePos() == previousXAxisTile));
|
||||
}
|
||||
else
|
||||
|
@ -281,6 +281,8 @@ CGObjectInstance * BoatInstanceConstructor::create(std::shared_ptr<const ObjectT
|
||||
boat->actualAnimation = actualAnimation;
|
||||
boat->overlayAnimation = overlayAnimation;
|
||||
boat->flagAnimations = flagAnimations;
|
||||
boat->onboardAssaultAllowed = onboardAssaultAllowed;
|
||||
boat->onboardVisitAllowed = onboardVisitAllowed;
|
||||
for(auto & b : bonuses)
|
||||
boat->addNewBonus(std::make_shared<Bonus>(b));
|
||||
|
||||
|
@ -437,28 +437,43 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
|
||||
}
|
||||
else if(ID == Obj::PRISON)
|
||||
{
|
||||
int txt_id;
|
||||
|
||||
if (cb->getHeroCount(h->tempOwner, false) < VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))//free hero slot
|
||||
{
|
||||
//update hero parameters
|
||||
SetMovePoints smp;
|
||||
smp.hid = id;
|
||||
smp.val = maxMovePoints (true); //TODO: hota prison on water?
|
||||
|
||||
cb->setManaPoints (id, manaLimit());
|
||||
|
||||
ObjectInstanceID boatId;
|
||||
const auto boatPos = visitablePos();
|
||||
if (cb->gameState()->map->getTile(boatPos).isWater())
|
||||
{
|
||||
smp.val = maxMovePoints(false);
|
||||
//Create a new boat for hero
|
||||
NewObject no;
|
||||
no.ID = Obj::BOAT;
|
||||
no.subID = BoatId(EBoatId::BOAT_NEUTRAL);
|
||||
no.pos = CGBoat::translatePos(boatPos);
|
||||
|
||||
cb->sendAndApply(&no);
|
||||
|
||||
boatId = cb->getTopObj(boatPos)->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
smp.val = maxMovePoints(true);
|
||||
}
|
||||
cb->giveHero(id, h->tempOwner, boatId); //recreates def and adds hero to player
|
||||
cb->setObjProperty(id, ObjProperty::ID, Obj::HERO); //set ID to 34 AFTER hero gets correct flag color
|
||||
cb->setMovePoints (&smp);
|
||||
cb->setManaPoints (id, manaLimit());
|
||||
|
||||
cb->setObjProperty(id, ObjProperty::ID, Obj::HERO); //set ID to 34
|
||||
cb->giveHero(id,h->tempOwner); //recreates def and adds hero to player
|
||||
|
||||
txt_id = 102;
|
||||
h->showInfoDialog(102);
|
||||
}
|
||||
else //already 8 wandering heroes
|
||||
{
|
||||
txt_id = 103;
|
||||
h->showInfoDialog(103);
|
||||
}
|
||||
|
||||
h->showInfoDialog(txt_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -939,11 +954,11 @@ si32 CGHeroInstance::getManaNewTurn() const
|
||||
|
||||
BoatId CGHeroInstance::getBoatType() const
|
||||
{
|
||||
switch(type->heroClass->getAlignment())
|
||||
switch (type->heroClass->getAlignment())
|
||||
{
|
||||
case EAlignment::EVIL : return EBoatId::BOAT_EVIL;
|
||||
case EAlignment::GOOD : return EBoatId::BOAT_GOOD;
|
||||
case EAlignment::NEUTRAL : return EBoatId::BOAT_NEUTRAL;
|
||||
case EAlignment::EVIL: return EBoatId::BOAT_EVIL;
|
||||
case EAlignment::GOOD: return EBoatId::BOAT_GOOD;
|
||||
case EAlignment::NEUTRAL: return EBoatId::BOAT_NEUTRAL;
|
||||
default: return EBoatId::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -1858,6 +1858,22 @@ void CGBoat::initObj(CRandomGenerator & rand)
|
||||
hero = nullptr;
|
||||
}
|
||||
|
||||
int3 CGBoat::translatePos(const int3& pos, bool reverse /* = false */)
|
||||
{
|
||||
//pos - offset we want to place the boat at the map
|
||||
//returned value - actual position as seen by game mechanics
|
||||
|
||||
//If reverse = true, then it's the opposite.
|
||||
if (!reverse)
|
||||
{
|
||||
return pos + int3(1, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return pos - int3(1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CGSirens::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
blockVisit = true;
|
||||
|
@ -430,6 +430,7 @@ public:
|
||||
std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations;
|
||||
|
||||
void initObj(CRandomGenerator & rand) override;
|
||||
static int3 translatePos(const int3 &pos, bool reverse = false);
|
||||
|
||||
CGBoat()
|
||||
{
|
||||
|
@ -29,6 +29,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
void ObjectDistributor::process()
|
||||
{
|
||||
distributeLimitedObjects();
|
||||
distributePrisons();
|
||||
distributeSeerHuts();
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ void TreasurePlacer::process()
|
||||
|
||||
void TreasurePlacer::init()
|
||||
{
|
||||
maxPrisons = 0; //Should be in the constructor, but we use macro for that
|
||||
DEPENDENCY(ObjectManager);
|
||||
DEPENDENCY(ConnectionsPlacer);
|
||||
POSTFUNCTION(RoadPlacer);
|
||||
@ -93,49 +94,54 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Generate Prison on water only if it has a template
|
||||
auto prisonTemplates = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0)->getTemplates(zone.getTerrainType());
|
||||
if (!prisonTemplates.empty())
|
||||
{
|
||||
//prisons
|
||||
//levels 1, 5, 10, 20, 30
|
||||
static int prisonsLevels = std::min(generator.getConfig().prisonExperience.size(), generator.getConfig().prisonValues.size());
|
||||
|
||||
size_t prisonsLeft = getMaxPrisons();
|
||||
for (int i = prisonsLevels - 1; i >= 0; i--)
|
||||
{
|
||||
oi.value = generator.getConfig().prisonValues[i];
|
||||
if (oi.value > zone.getMaxTreasureValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
oi.generateObject = [i, this]() -> CGObjectInstance*
|
||||
{
|
||||
auto possibleHeroes = generator.getAllPossibleHeroes();
|
||||
HeroTypeID hid = *RandomGeneratorUtil::nextItem(possibleHeroes, zone.getRand());
|
||||
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
|
||||
auto* obj = dynamic_cast<CGHeroInstance*>(factory->create());
|
||||
|
||||
obj->subID = hid; //will be initialized later
|
||||
obj->exp = generator.getConfig().prisonExperience[i];
|
||||
obj->setOwner(PlayerColor::NEUTRAL);
|
||||
generator.banHero(hid);
|
||||
obj->appearance = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0)->getTemplates(zone.getTerrainType()).front(); //can't init template with hero subID
|
||||
|
||||
return obj;
|
||||
};
|
||||
oi.setTemplate(Obj::PRISON, 0, zone.getTerrainType());
|
||||
oi.value = generator.getConfig().prisonValues[i];
|
||||
oi.probability = 30;
|
||||
|
||||
//Distribute all allowed prisons, starting from the most valuable
|
||||
oi.maxPerZone = (std::ceil((float)prisonsLeft / (i + 1)));
|
||||
prisonsLeft -= oi.maxPerZone;
|
||||
addObjectToRandomPool(oi);
|
||||
}
|
||||
}
|
||||
|
||||
if(zone.getType() == ETemplateZoneType::WATER)
|
||||
return;
|
||||
|
||||
//prisons
|
||||
//levels 1, 5, 10, 20, 30
|
||||
static int prisonsLevels = std::min(generator.getConfig().prisonExperience.size(), generator.getConfig().prisonValues.size());
|
||||
|
||||
size_t prisonsLeft = getMaxPrisons();
|
||||
for(int i = prisonsLevels - 1; i >= 0 ;i--)
|
||||
{
|
||||
oi.value = generator.getConfig().prisonValues[i];
|
||||
if (oi.value > zone.getMaxTreasureValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
oi.generateObject = [i, this]() -> CGObjectInstance *
|
||||
{
|
||||
auto possibleHeroes = generator.getAllPossibleHeroes();
|
||||
HeroTypeID hid = *RandomGeneratorUtil::nextItem(possibleHeroes, zone.getRand());
|
||||
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
|
||||
auto * obj = dynamic_cast<CGHeroInstance *>(factory->create());
|
||||
|
||||
obj->subID = hid; //will be initialized later
|
||||
obj->exp = generator.getConfig().prisonExperience[i];
|
||||
obj->setOwner(PlayerColor::NEUTRAL);
|
||||
generator.banHero(hid);
|
||||
obj->appearance = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0)->getTemplates(zone.getTerrainType()).front(); //can't init template with hero subID
|
||||
|
||||
return obj;
|
||||
};
|
||||
oi.setTemplate(Obj::PRISON, 0, zone.getTerrainType());
|
||||
oi.value = generator.getConfig().prisonValues[i];
|
||||
oi.probability = 30;
|
||||
|
||||
//Distribute all allowed prisons, starting from the most valuable
|
||||
oi.maxPerZone = (std::ceil((float)prisonsLeft / (i + 1)));
|
||||
prisonsLeft -= oi.maxPerZone;
|
||||
addObjectToRandomPool(oi);
|
||||
}
|
||||
|
||||
//all following objects are unlimited
|
||||
oi.maxPerZone = std::numeric_limits<ui32>::max();
|
||||
|
||||
|
@ -201,7 +201,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
{
|
||||
ChangeObjPos cop;
|
||||
cop.objid = nearest->id;
|
||||
cop.nPos = summonPos + int3(1,0,0);
|
||||
cop.nPos = CGBoat::translatePos(summonPos);
|
||||
env->apply(&cop);
|
||||
}
|
||||
else if(schoolLevel < 2) //none or basic level -> cannot create boat :(
|
||||
@ -215,8 +215,8 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
{
|
||||
NewObject no;
|
||||
no.ID = Obj::BOAT;
|
||||
no.subID = parameters.caster->getHeroCaster()->getBoatType().getNum();
|
||||
no.pos = summonPos + int3(1,0,0);
|
||||
no.subID = BoatId(EBoatId::BOAT_EVIL);
|
||||
no.pos = CGBoat::translatePos(summonPos);
|
||||
env->apply(&no);
|
||||
}
|
||||
return ESpellCastResult::OK;
|
||||
|
@ -2732,12 +2732,17 @@ void CGameHandler::setManaPoints(ObjectInstanceID hid, int val)
|
||||
sendAndApply(&sm);
|
||||
}
|
||||
|
||||
void CGameHandler::giveHero(ObjectInstanceID id, PlayerColor player)
|
||||
void CGameHandler::giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId)
|
||||
{
|
||||
GiveHero gh;
|
||||
gh.id = id;
|
||||
gh.player = player;
|
||||
gh.boatId = boatId;
|
||||
sendAndApply(&gh);
|
||||
|
||||
//Reveal fow around new hero, especially released from Prison
|
||||
auto h = getHero(id);
|
||||
changeFogOfWar(h->pos, h->getSightRadius(), player, false);
|
||||
}
|
||||
|
||||
void CGameHandler::changeObjPos(ObjectInstanceID objid, int3 newPos)
|
||||
@ -4411,6 +4416,17 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
|
||||
hr.hid = nh->subID;
|
||||
hr.player = player;
|
||||
hr.tile = nh->convertFromVisitablePos(obj->visitablePos());
|
||||
if (getTile(hr.tile)->isWater())
|
||||
{
|
||||
//Create a new boat for hero
|
||||
NewObject no;
|
||||
no.ID = Obj::BOAT;
|
||||
no.subID = BoatId(EBoatId::BOAT_NEUTRAL);
|
||||
no.pos = hr.tile + int3(1,0,0);
|
||||
sendAndApply(&no);
|
||||
|
||||
hr.boatId = getTopObj(hr.tile)->id;
|
||||
}
|
||||
sendAndApply(&hr);
|
||||
|
||||
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > pool = gs->unusedHeroesFromPool();
|
||||
|
@ -195,7 +195,7 @@ public:
|
||||
void giveHeroBonus(GiveBonus * bonus) override;
|
||||
void setMovePoints(SetMovePoints * smp) override;
|
||||
void setManaPoints(ObjectInstanceID hid, int val) override;
|
||||
void giveHero(ObjectInstanceID id, PlayerColor player) override;
|
||||
void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override;
|
||||
void changeObjPos(ObjectInstanceID objid, int3 newPos) override;
|
||||
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override;
|
||||
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
void giveHeroBonus(GiveBonus * bonus) override {}
|
||||
void setMovePoints(SetMovePoints * smp) override {}
|
||||
void setManaPoints(ObjectInstanceID hid, int val) override {}
|
||||
void giveHero(ObjectInstanceID id, PlayerColor player) override {}
|
||||
void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override {}
|
||||
void changeObjPos(ObjectInstanceID objid, int3 newPos) override {}
|
||||
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {} //when two heroes meet on adventure map
|
||||
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {}
|
||||
|
Loading…
Reference in New Issue
Block a user