1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00

Implemented support for fixed monster def's from hota

This commit is contained in:
Ivan Savenko
2023-06-17 18:07:25 +03:00
parent 6f743916db
commit 8dde8018d0
6 changed files with 33 additions and 18 deletions

View File

@@ -625,17 +625,25 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
registerObject(scope, type_name, extraName.String(), cre->getIndex()); registerObject(scope, type_name, extraName.String(), cre->getIndex());
} }
JsonNode advMapFile = node["graphics"]["map"];
JsonNode advMapMask = node["graphics"]["mapMask"];
VLC->modh->identifiers.requestIdentifier(scope, "object", "monster", [=](si32 index) VLC->modh->identifiers.requestIdentifier(scope, "object", "monster", [=](si32 index)
{ {
JsonNode conf; JsonNode conf;
conf.setMeta(scope); conf.setMeta(scope);
VLC->objtypeh->loadSubObject(cre->identifier, conf, Obj::MONSTER, cre->getId().num); VLC->objtypeh->loadSubObject(cre->identifier, conf, Obj::MONSTER, cre->getId().num);
if (!cre->advMapDef.empty()) if (!advMapFile.isNull())
{ {
JsonNode templ; JsonNode templ;
templ["animation"].String() = cre->advMapDef; templ["animation"] = advMapFile;
if (!advMapMask.isNull())
templ["mask"] = advMapMask;
templ.setMeta(scope); templ.setMeta(scope);
// if creature has custom advMapFile, reset any potentially imported H3M templates and use provided file instead
VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->clearTemplates();
VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->addTemplate(templ); VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->addTemplate(templ);
} }
@@ -871,7 +879,6 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph
cre->animation.attackClimaxFrame = static_cast<int>(missile["attackClimaxFrame"].Float()); cre->animation.attackClimaxFrame = static_cast<int>(missile["attackClimaxFrame"].Float());
cre->animation.missleFrameAngles = missile["frameAngles"].convertTo<std::vector<double> >(); cre->animation.missleFrameAngles = missile["frameAngles"].convertTo<std::vector<double> >();
cre->advMapDef = graphics["map"].String();
cre->smallIconName = graphics["iconSmall"].String(); cre->smallIconName = graphics["iconSmall"].String();
cre->largeIconName = graphics["iconLarge"].String(); cre->largeIconName = graphics["iconLarge"].String();
} }

View File

@@ -58,7 +58,6 @@ public:
std::set<CreatureID> upgrades; // IDs of creatures to which this creature can be upgraded std::set<CreatureID> upgrades; // IDs of creatures to which this creature can be upgraded
std::string animDefName; // creature animation used during battles std::string animDefName; // creature animation used during battles
std::string advMapDef; //for new creatures only, image for adventure map
si32 iconIndex = -1; // index of icon in files like twcrport, used in tests now. si32 iconIndex = -1; // index of icon in files like twcrport, used in tests now.
/// names of files with appropriate icons. Used only during loading /// names of files with appropriate icons. Used only during loading
@@ -230,7 +229,6 @@ public:
h & ammMax; h & ammMax;
h & level; h & level;
h & animDefName; h & animDefName;
h & advMapDef;
h & iconIndex; h & iconIndex;
h & smallIconName; h & smallIconName;
h & largeIconName; h & largeIconName;

View File

@@ -649,7 +649,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
std::pair<Obj,int> ran = pickObject(cur); std::pair<Obj,int> ran = pickObject(cur);
if(ran.first == Obj::NO_OBJ || ran.second<0) //this is not a random object, or we couldn't find anything if(ran.first == Obj::NO_OBJ || ran.second<0) //this is not a random object, or we couldn't find anything
{ {
if(cur->ID==Obj::TOWN) if(cur->ID==Obj::TOWN || cur->ID==Obj::MONSTER)
cur->setType(cur->ID, cur->subID); // update def, if necessary cur->setType(cur->ID, cur->subID); // update def, if necessary
} }
else if(ran.first==Obj::HERO)//special code for hero else if(ran.first==Obj::HERO)//special code for hero

View File

@@ -148,6 +148,11 @@ SObjectSounds AObjectTypeHandler::getSounds() const
return sounds; return sounds;
} }
void AObjectTypeHandler::clearTemplates()
{
templates.clear();
}
void AObjectTypeHandler::addTemplate(const std::shared_ptr<const ObjectTemplate> & templ) void AObjectTypeHandler::addTemplate(const std::shared_ptr<const ObjectTemplate> & templ)
{ {
templates.push_back(templ); templates.push_back(templ);

View File

@@ -70,6 +70,7 @@ public:
void addTemplate(const std::shared_ptr<const ObjectTemplate> & templ); void addTemplate(const std::shared_ptr<const ObjectTemplate> & templ);
void addTemplate(JsonNode config); void addTemplate(JsonNode config);
void clearTemplates();
/// returns all templates matching parameters /// returns all templates matching parameters
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates() const; std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates() const;

View File

@@ -105,7 +105,7 @@ std::set<int3> CGObjectInstance::getBlockedOffsets() const
return appearance->getBlockedOffsets(); return appearance->getBlockedOffsets();
} }
void CGObjectInstance::setType(si32 ID, si32 subID) void CGObjectInstance::setType(si32 newID, si32 newSubID)
{ {
auto position = visitablePos(); auto position = visitablePos();
auto oldOffset = getVisitableOffset(); auto oldOffset = getVisitableOffset();
@@ -113,10 +113,10 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
//recalculate blockvis tiles - new appearance might have different blockmap than before //recalculate blockvis tiles - new appearance might have different blockmap than before
cb->gameState()->map->removeBlockVisTiles(this, true); cb->gameState()->map->removeBlockVisTiles(this, true);
auto handler = VLC->objtypeh->getHandlerFor(ID, subID); auto handler = VLC->objtypeh->getHandlerFor(newID, newSubID);
if(!handler) if(!handler)
{ {
logGlobal->error("Unknown object type %d:%d at %s", ID, subID, visitablePos().toString()); logGlobal->error("Unknown object type %d:%d at %s", newID, newSubID, visitablePos().toString());
return; return;
} }
if(!handler->getTemplates(tile.terType->getId()).empty()) if(!handler->getTemplates(tile.terType->getId()).empty())
@@ -125,22 +125,26 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
} }
else else
{ {
logGlobal->warn("Object %d:%d at %s has no templates suitable for terrain %s", ID, subID, visitablePos().toString(), tile.terType->getNameTranslated()); logGlobal->warn("Object %d:%d at %s has no templates suitable for terrain %s", newID, newSubID, visitablePos().toString(), tile.terType->getNameTranslated());
appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
} }
if(this->ID == Obj::PRISON && ID == Obj::HERO) bool needToAdjustOffset = false;
{
auto newOffset = getVisitableOffset();
// FIXME: potentially unused code - setType is NOT called when releasing hero from prison
// instead, appearance update & pos adjustment occurs in GiveHero::applyGs
// adjust position since hero and prison may have different visitable offset // FIXME: potentially unused code - setType is NOT called when releasing hero from prison
// instead, appearance update & pos adjustment occurs in GiveHero::applyGs
needToAdjustOffset |= this->ID == Obj::PRISON && newID == Obj::HERO;
needToAdjustOffset |= newID == Obj::MONSTER;
if(needToAdjustOffset)
{
// adjust position since object visitable offset might have changed
auto newOffset = getVisitableOffset();
pos = pos - oldOffset + newOffset; pos = pos - oldOffset + newOffset;
} }
this->ID = Obj(ID); this->ID = Obj(newID);
this->subID = subID; this->subID = newSubID;
cb->gameState()->map->addBlockVisTiles(this); cb->gameState()->map->addBlockVisTiles(this);
} }