1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Cleaned up dwelling randomization

This commit is contained in:
Ivan Savenko 2023-10-25 21:56:00 +03:00
parent dcb8f4fc7b
commit 7a09646009
12 changed files with 69 additions and 105 deletions

View File

@ -77,34 +77,6 @@ public:
}
};
static CGObjectInstance * createObject(MapObjectID id, MapObjectSubID subid, const int3 & pos, const PlayerColor & owner)
{
CGObjectInstance * nobj;
switch(id)
{
case Obj::HERO:
{
auto handler = VLC->objtypeh->getHandlerFor(id, VLC->heroh->objects[subid]->heroClass->getIndex());
nobj = handler->create(handler->getTemplates().front());
break;
}
case Obj::TOWN:
nobj = new CGTownInstance();
break;
default: //rest of objects
nobj = new CGObjectInstance();
break;
}
nobj->ID = id;
nobj->subID = subid;
nobj->pos = pos;
nobj->tempOwner = owner;
if (id != Obj::HERO)
nobj->appearance = VLC->objtypeh->getHandlerFor(id, subid)->getTemplates().front();
return nobj;
}
HeroTypeID CGameState::pickNextHeroType(const PlayerColor & owner)
{
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
@ -547,44 +519,30 @@ void CGameState::initRandomFactionsForPlayers()
void CGameState::randomizeMapObjects()
{
logGlobal->debug("\tRandomizing objects");
for(CGObjectInstance *obj : map->objects)
for(CGObjectInstance *object : map->objects)
{
if(!obj)
if(!object)
continue;
{
std::pair<Obj,int> ran = pickObject(obj);
if(ran.first == Obj::NO_OBJ || ran.second<0) //this is not a random object, or we couldn't find anything
{
if(obj->ID==Obj::TOWN || obj->ID==Obj::MONSTER)
obj->setType(obj->ID, obj->subID); // update def, if necessary
}
else if(ran.first==Obj::HERO)//special code for hero
{
auto * h = dynamic_cast<CGHeroInstance *>(obj);
obj->setType(ran.first, ran.second);
map->heroesOnMap.emplace_back(h);
}
else if(ran.first==Obj::TOWN)//special code for town
{
auto * t = dynamic_cast<CGTownInstance *>(obj);
obj->setType(ran.first, ran.second);
map->towns.emplace_back(t);
}
else
{
obj->setType(ran.first, ran.second);
}
}
object->pickRandomObject(getRandomGenerator());
auto * hero = dynamic_cast<CGHeroInstance *>(object);
auto * town = dynamic_cast<CGTownInstance *>(object);
if (hero)
map->heroesOnMap.emplace_back(hero);
if (town)
map->towns.emplace_back(town);
//handle Favouring Winds - mark tiles under it
if(obj->ID == Obj::FAVORABLE_WINDS)
if(object->ID == Obj::FAVORABLE_WINDS)
{
for (int i = 0; i < obj->getWidth() ; i++)
for (int i = 0; i < object->getWidth() ; i++)
{
for (int j = 0; j < obj->getHeight() ; j++)
for (int j = 0; j < object->getHeight() ; j++)
{
int3 pos = obj->pos - int3(i,j,0);
int3 pos = object->pos - int3(i,j,0);
if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
}
}
@ -617,7 +575,14 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
}
}
CGObjectInstance * hero = createObject(Obj::HERO, heroTypeId, townPos, playerColor);
auto handler = VLC->objtypeh->getHandlerFor(Obj::HERO, VLC->heroh->objects[heroTypeId]->heroClass->getIndex());
CGObjectInstance * hero = handler->create(handler->getTemplates().front());
hero->ID = Obj::HERO;
hero->subID = VLC->heroh->objects[heroTypeId]->heroClass->getIndex();
hero->tempOwner = playerColor;
hero->pos = townPos;
hero->pos += hero->getVisitableOffset();
map->getEditManager()->insertObject(hero);
}

View File

@ -115,6 +115,8 @@ public:
void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
bool giveHeroArtifact(CGHeroInstance * h, const ArtifactID & aid);
/// picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
HeroTypeID pickNextHeroType(const PlayerColor & owner);
void apply(CPack *pack);
BattleField battleGetBattlefieldType(int3 tile, CRandomGenerator & rand);
@ -214,7 +216,6 @@ private:
bool isUsedHero(const HeroTypeID & hid) const; //looks in heroes and prisons
std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
HeroTypeID pickUnusedHeroTypeRandomly(const PlayerColor & owner); // picks a unused hero type randomly
HeroTypeID pickNextHeroType(const PlayerColor & owner); // picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
UpgradeInfo fillUpgradeInfo(const CStackInstance &stack) const;
// ---- data -----

View File

@ -152,7 +152,6 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
break;
}
}
}
CreatureID CGCreature::getCreature() const

View File

@ -48,6 +48,10 @@ CGDwelling::~CGDwelling() = default;
FactionID CGDwelling::randomizeFaction(CRandomGenerator & rand)
{
if (ID == Obj::RANDOM_DWELLING_FACTION)
return FactionID(subID);
assert(ID == Obj::RANDOM_DWELLING || ID == Obj::RANDOM_DWELLING_LVL);
assert(randomizationInfo.has_value());
if (!randomizationInfo)
return FactionID::CASTLE;
@ -102,6 +106,10 @@ FactionID CGDwelling::randomizeFaction(CRandomGenerator & rand)
int CGDwelling::randomizeLevel(CRandomGenerator & rand)
{
if (ID == Obj::RANDOM_DWELLING_LVL)
return subID.getNum();
assert(ID == Obj::RANDOM_DWELLING || ID == Obj::RANDOM_DWELLING_FACTION);
assert(randomizationInfo.has_value());
if (!randomizationInfo)

View File

@ -296,16 +296,6 @@ void CGHeroInstance::initHero(CRandomGenerator & rand, const HeroTypeID & SUBID)
initHero(rand);
}
void CGHeroInstance::setType(si32 ID, si32 subID)
{
assert(ID == Obj::HERO); // just in case
type = VLC->heroh->objects[subID];
CGObjectInstance::setType(ID, type->heroClass->getIndex()); // to find object handler we must use heroClass->id
this->subID = subID; // after setType subID used to store unique hero identify id. Check issue 2277 for details
randomizeArmy(type->heroClass->faction);
}
void CGHeroInstance::initHero(CRandomGenerator & rand)
{
assert(validTypes(true));
@ -580,6 +570,14 @@ void CGHeroInstance::pickRandomObject(CRandomGenerator & rand)
ID = Obj::HERO;
subID = cb->gameState()->pickNextHeroType(getOwner());
}
type = VLC->heroh->objects[subID];
// to find object handler we must use heroClass->id
// after setType subID used to store unique hero identify id. Check issue 2277 for details
setType(ID, type->heroClass->getIndex());
this->subID = subID;
randomizeArmy(type->heroClass->faction);
}
void CGHeroInstance::initObj(CRandomGenerator & rand)

View File

@ -232,7 +232,6 @@ public:
//////////////////////////////////////////////////////////////////////////
HeroTypeID getHeroType() const;
void setType(si32 ID, si32 subID) override;
void initHero(CRandomGenerator & rand);
void initHero(CRandomGenerator & rand, const HeroTypeID & SUBID);

View File

@ -106,10 +106,6 @@ public:
virtual int getSightRadius() const;
/// returns (x,y,0) offset to a visitable tile of object
virtual int3 getVisitableOffset() const;
/// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman")
virtual void setType(si32 ID, si32 subID);
/// returns text visible in status bar with specific hero/player active.
/// Returns generic name of object, without any player-specific info
virtual std::string getObjectName() const;
@ -160,6 +156,9 @@ protected:
/// virtual method that allows synchronously update object state on server and all clients
virtual void setPropertyDer(ui8 what, ui32 val);
/// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman")
void setType(si32 ID, si32 subID);
/// Gives dummy bonus from this object to hero. Can be used to track visited state
void giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration::Type duration = BonusDuration::ONE_DAY) const;

View File

@ -486,6 +486,12 @@ void CGTownInstance::pickRandomObject(CRandomGenerator & rand)
ID = MapObjectID::TOWN;
subID = randomizeFaction(rand);
}
assert(ID == Obj::TOWN); // just in case
setType(ID, subID);
town = (*VLC->townh)[subID]->town;
randomizeArmy(subID);
updateAppearance();
}
void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures
@ -779,15 +785,6 @@ std::vector<int> CGTownInstance::availableItemsIds(EMarketMode mode) const
return IMarket::availableItemsIds(mode);
}
void CGTownInstance::setType(si32 ID, si32 subID)
{
assert(ID == Obj::TOWN); // just in case
CGObjectInstance::setType(ID, subID);
town = (*VLC->townh)[subID]->town;
randomizeArmy(subID);
updateAppearance();
}
void CGTownInstance::updateAppearance()
{
auto terrain = cb->gameState()->getTile(visitablePos())->terType->getId();

View File

@ -141,7 +141,6 @@ public:
bool allowsTrade(EMarketMode mode) const override;
std::vector<int> availableItemsIds(EMarketMode mode) const override;
void setType(si32 ID, si32 subID) override;
void updateAppearance();
//////////////////////////////////////////////////////////////////////////

View File

@ -46,6 +46,9 @@ void IObjectInterface::newTurn(CRandomGenerator & rand) const
void IObjectInterface::initObj(CRandomGenerator & rand)
{}
void IObjectInterface::pickRandomObject(CRandomGenerator & rand)
{}
void IObjectInterface::setProperty( ui8 what, ui32 val )
{}

View File

@ -1336,12 +1336,19 @@ CGObjectInstance * CMapLoaderH3M::readDwellingRandom(const int3 & mapPosition, s
if(object->randomizationInfo->identifier != 0)
reader->readBitmaskFactions(object->randomizationInfo->allowedFactions, false);
}
else
object->randomizationInfo->allowedFactions.insert(FactionID(objectTemplate->subid));
if(hasLevelInfo)
{
object->randomizationInfo->minLevel = std::max(reader->readUInt8(), static_cast<ui8>(0)) + 1;
object->randomizationInfo->maxLevel = std::min(reader->readUInt8(), static_cast<ui8>(6)) + 1;
}
else
{
object->randomizationInfo->minLevel = objectTemplate->subid;
object->randomizationInfo->maxLevel = objectTemplate->subid;
}
return object;
}

View File

@ -87,14 +87,6 @@ void Initializer::initialize(CGDwelling * o)
if(!o) return;
o->tempOwner = defaultPlayer;
switch(o->ID)
{
case Obj::RANDOM_DWELLING:
case Obj::RANDOM_DWELLING_LVL:
case Obj::RANDOM_DWELLING_FACTION:
o->initRandomObjectInfo();
}
}
void Initializer::initialize(CGGarrison * o)
@ -243,11 +235,8 @@ void Inspector::updateProperties(CGDwelling * o)
addProperty("Owner", o->tempOwner, false);
if(dynamic_cast<CCreGenAsCastleInfo*>(o->info))
{
auto * delegate = new PickObjectDelegate(controller, PickObjectDelegate::typedFilter<CGTownInstance>);
addProperty("Same as town", PropertyEditorPlaceholder(), delegate, false);
}
auto * delegate = new PickObjectDelegate(controller, PickObjectDelegate::typedFilter<CGTownInstance>);
addProperty("Same as town", PropertyEditorPlaceholder(), delegate, false);
}
void Inspector::updateProperties(CGLighthouse * o)
@ -641,12 +630,12 @@ void Inspector::setProperty(CGDwelling * o, const QString & key, const QVariant
if(key == "Same as town")
{
if(auto * info = dynamic_cast<CCreGenAsCastleInfo*>(o->info))
{
info->instanceId = "";
if(CGTownInstance * town = data_cast<CGTownInstance>(value.toLongLong()))
info->instanceId = town->instanceName;
}
if (!o->randomizationInfo.has_value())
o->randomizationInfo = CGDwellingRandomizationInfo();
o->randomizationInfo->instanceId = "";
if(CGTownInstance * town = data_cast<CGTownInstance>(value.toLongLong()))
o->randomizationInfo->instanceId = town->instanceName;
}
}