1
0
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:
DjWarmonger 2023-06-16 16:30:05 +02:00 committed by GitHub
commit c52b5d3bd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 156 additions and 66 deletions

View File

@ -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 {};

View File

@ -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

View File

@ -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;
}
};

View File

@ -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

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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()
{

View File

@ -29,6 +29,7 @@ VCMI_LIB_NAMESPACE_BEGIN
void ObjectDistributor::process()
{
distributeLimitedObjects();
distributePrisons();
distributeSeerHuts();
}

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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 {}