mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
Implemented (basic) object construction and placement
* contain refactoring of RMG and class handling (will be more)
This commit is contained in:
@@ -207,6 +207,28 @@ void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode
|
||||
|
||||
artifacts.push_back(object);
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier(scope, "object", "artifact", [=](si32 index)
|
||||
{
|
||||
JsonNode conf;
|
||||
conf.setMeta(scope);
|
||||
|
||||
VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::ARTIFACT, object->id.num);
|
||||
|
||||
if (!object->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ.setMeta(scope);
|
||||
templ["animation"].String() = object->advMapDef;
|
||||
|
||||
// add new template.
|
||||
// Necessary for objects added via mods that don't have any templates in H3
|
||||
VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->addTemplate(templ);
|
||||
}
|
||||
// object does not have any templates - this is not usable object (e.g. pseudo-art like lock)
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->getTemplates().empty())
|
||||
VLC->objtypeh->removeSubObject(Obj::ARTIFACT, object->id);
|
||||
});
|
||||
|
||||
registerObject(scope, "artifact", object->identifier, object->id);
|
||||
}
|
||||
|
||||
@@ -219,6 +241,27 @@ void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode
|
||||
assert(artifacts[index] == nullptr); // ensure that this id was not loaded before
|
||||
artifacts[index] = object;
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier(scope, "object", "artifact", [=](si32 index)
|
||||
{
|
||||
JsonNode conf;
|
||||
conf.setMeta(scope);
|
||||
|
||||
VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::ARTIFACT, object->id.num);
|
||||
|
||||
if (!object->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ.setMeta(scope);
|
||||
templ["animation"].String() = object->advMapDef;
|
||||
|
||||
// add new template.
|
||||
// Necessary for objects added via mods that don't have any templates in H3
|
||||
VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->addTemplate(templ);
|
||||
}
|
||||
// object does not have any templates - this is not usable object (e.g. pseudo-art like lock)
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->getTemplates().empty())
|
||||
VLC->objtypeh->removeSubObject(Obj::ARTIFACT, object->id);
|
||||
});
|
||||
registerObject(scope, "artifact", object->identifier, object->id);
|
||||
}
|
||||
|
||||
@@ -694,24 +737,6 @@ void CArtHandler::afterLoadFinalization()
|
||||
bonus->sid = art->id;
|
||||
}
|
||||
}
|
||||
|
||||
for (CArtifact * art : artifacts)
|
||||
{
|
||||
VLC->objtypeh->loadSubObject(art->Name(), JsonNode(), Obj::ARTIFACT, art->id.num);
|
||||
|
||||
if (!art->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ["animation"].String() = art->advMapDef;
|
||||
|
||||
// add new template.
|
||||
// Necessary for objects added via mods that don't have any templates in H3
|
||||
VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->addTemplate(templ);
|
||||
}
|
||||
// object does not have any templates - this is not usable object (e.g. pseudo-art like lock)
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->getTemplates().empty())
|
||||
VLC->objtypeh->removeSubObject(Obj::ARTIFACT, art->id);
|
||||
}
|
||||
}
|
||||
|
||||
CArtifactInstance::CArtifactInstance()
|
||||
|
@@ -363,6 +363,24 @@ void CCreatureHandler::loadObject(std::string scope, std::string name, const Jso
|
||||
|
||||
creatures.push_back(object);
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier(scope, "object", "monster", [=](si32 index)
|
||||
{
|
||||
JsonNode conf;
|
||||
conf.setMeta(scope);
|
||||
|
||||
VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::MONSTER, object->idNumber.num);
|
||||
if (!object->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ["animation"].String() = object->advMapDef;
|
||||
VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->addTemplate(templ);
|
||||
}
|
||||
|
||||
// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower)
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->getTemplates().empty())
|
||||
VLC->objtypeh->removeSubObject(Obj::MONSTER, object->idNumber.num);
|
||||
});
|
||||
|
||||
registerObject(scope, "creature", name, object->idNumber);
|
||||
|
||||
for(auto node : data["extraNames"].Vector())
|
||||
@@ -385,6 +403,24 @@ void CCreatureHandler::loadObject(std::string scope, std::string name, const Jso
|
||||
assert(creatures[index] == nullptr); // ensure that this id was not loaded before
|
||||
creatures[index] = object;
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier(scope, "object", "monster", [=](si32 index)
|
||||
{
|
||||
JsonNode conf;
|
||||
conf.setMeta(scope);
|
||||
|
||||
VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::MONSTER, object->idNumber.num);
|
||||
if (!object->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ["animation"].String() = object->advMapDef;
|
||||
VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->addTemplate(templ);
|
||||
}
|
||||
|
||||
// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower)
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->getTemplates().empty())
|
||||
VLC->objtypeh->removeSubObject(Obj::MONSTER, object->idNumber.num);
|
||||
});
|
||||
|
||||
registerObject(scope, "creature", name, object->idNumber);
|
||||
for(auto & node : data["extraNames"].Vector())
|
||||
{
|
||||
@@ -1124,20 +1160,7 @@ void CCreatureHandler::buildBonusTreeForTiers()
|
||||
|
||||
void CCreatureHandler::afterLoadFinalization()
|
||||
{
|
||||
for (CCreature * crea : creatures)
|
||||
{
|
||||
VLC->objtypeh->loadSubObject(crea->nameSing, JsonNode(), Obj::MONSTER, crea->idNumber.num);
|
||||
if (!crea->advMapDef.empty())
|
||||
{
|
||||
JsonNode templ;
|
||||
templ["animation"].String() = crea->advMapDef;
|
||||
VLC->objtypeh->getHandlerFor(Obj::MONSTER, crea->idNumber)->addTemplate(templ);
|
||||
}
|
||||
|
||||
// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower)
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, crea->idNumber.num)->getTemplates().empty())
|
||||
VLC->objtypeh->removeSubObject(Obj::MONSTER, crea->idNumber.num);
|
||||
}
|
||||
}
|
||||
|
||||
void CCreatureHandler::deserializationFix()
|
||||
|
@@ -205,6 +205,13 @@ void CHeroClassHandler::loadObject(std::string scope, std::string name, const Js
|
||||
VLC->objtypeh->loadSubObject(name, classConf, index, object->id);
|
||||
});
|
||||
|
||||
// VLC->modh->identifiers.requestIdentifier(scope, "object", "prison", [=](si32 index)
|
||||
// {
|
||||
// JsonNode conf;
|
||||
// conf.setMeta(scope);
|
||||
// VLC->objtypeh->loadSubObject(name, conf, index, object->id);
|
||||
// });
|
||||
|
||||
VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id);
|
||||
}
|
||||
|
||||
|
@@ -186,6 +186,7 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std
|
||||
checkIdentifier(fullID);
|
||||
|
||||
registeredObjects.insert(std::make_pair(fullID, data));
|
||||
logGlobal->traceStream() << scope << "::" << fullID;
|
||||
}
|
||||
|
||||
std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdentifiers(const ObjectCallback & request)
|
||||
|
@@ -74,7 +74,6 @@ CObjectClassesHandler::CObjectClassesHandler()
|
||||
SET_HANDLER("pandora", CGPandoraBox);
|
||||
SET_HANDLER("pickable", CGPickable);
|
||||
SET_HANDLER("prison", CGHeroInstance);
|
||||
SET_HANDLER("prison", CGHeroInstance);
|
||||
SET_HANDLER("questGuard", CGQuestGuard);
|
||||
SET_HANDLER("resource", CGResource);
|
||||
SET_HANDLER("scholar", CGScholar);
|
||||
@@ -148,17 +147,18 @@ si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID)
|
||||
return defaultID; // some H3M objects loaded, first modded found
|
||||
}
|
||||
|
||||
void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj)
|
||||
void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj)
|
||||
{
|
||||
if (!handlerConstructors.count(obj->handlerName))
|
||||
{
|
||||
logGlobal->errorStream() << "Handler with name " << obj->handlerName << " was not found!";
|
||||
return;
|
||||
}
|
||||
si32 id = selectNextID(entry["index"], obj->objects, 1000);
|
||||
si32 id = selectNextID(entry["index"], obj->subObjects, 1000);
|
||||
|
||||
auto handler = handlerConstructors.at(obj->handlerName)();
|
||||
handler->setType(obj->id, id);
|
||||
handler->setTypeName(obj->identifier, identifier);
|
||||
|
||||
if (customNames.count(obj->id) && customNames.at(obj->id).size() > id)
|
||||
handler->init(entry, customNames.at(obj->id).at(id));
|
||||
@@ -175,50 +175,49 @@ void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContai
|
||||
legacyTemplates.erase(range.first, range.second);
|
||||
}
|
||||
|
||||
logGlobal->debugStream() << "Loaded object " << obj->id << ":" << id;
|
||||
assert(!obj->objects.count(id)); // DO NOT override
|
||||
obj->objects[id] = handler;
|
||||
logGlobal->debugStream() << "Loaded object " << obj->identifier << "(" << obj->id << ")" << ":" << identifier << "(" << id << ")" ;
|
||||
assert(!obj->subObjects.count(id)); // DO NOT override
|
||||
obj->subObjects[id] = handler;
|
||||
obj->subIds[identifier] = id;//todo: scope
|
||||
}
|
||||
|
||||
CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json)
|
||||
CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json, const std::string & name)
|
||||
{
|
||||
auto obj = new ObjectContainter();
|
||||
obj->identifier = name;
|
||||
obj->name = json["name"].String();
|
||||
obj->handlerName = json["handler"].String();
|
||||
obj->base = json["base"];
|
||||
obj->id = selectNextID(json["index"], objects, 256);
|
||||
for (auto entry : json["types"].Struct())
|
||||
{
|
||||
loadObjectEntry(entry.second, obj);
|
||||
loadObjectEntry(entry.first, entry.second, obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
|
||||
{
|
||||
auto object = loadFromJson(data);
|
||||
auto object = loadFromJson(data, name);
|
||||
objects[object->id] = object;
|
||||
|
||||
VLC->modh->identifiers.registerObject(scope, "object", name, object->id);
|
||||
}
|
||||
|
||||
void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
|
||||
{
|
||||
auto object = loadFromJson(data);
|
||||
|
||||
auto object = loadFromJson(data, name);
|
||||
assert(objects[index] == nullptr); // ensure that this id was not loaded before
|
||||
objects[index] = object;
|
||||
|
||||
VLC->modh->identifiers.registerObject(scope, "object", name, object->id);
|
||||
}
|
||||
|
||||
void CObjectClassesHandler::loadSubObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID)
|
||||
void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID)
|
||||
{
|
||||
config.setType(JsonNode::DATA_STRUCT); // ensure that input is not NULL
|
||||
assert(objects.count(ID));
|
||||
if (subID)
|
||||
{
|
||||
assert(objects.at(ID)->objects.count(subID.get()) == 0);
|
||||
assert(objects.at(ID)->subObjects.count(subID.get()) == 0);
|
||||
assert(config["index"].isNull());
|
||||
config["index"].Float() = subID.get();
|
||||
}
|
||||
@@ -227,14 +226,14 @@ void CObjectClassesHandler::loadSubObject(std::string name, JsonNode config, si3
|
||||
JsonUtils::inherit(config, objects.at(ID)->base);
|
||||
config.setMeta(oldMeta);
|
||||
|
||||
loadObjectEntry(config, objects[ID]);
|
||||
loadObjectEntry(identifier, config, objects[ID]);
|
||||
}
|
||||
|
||||
void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID)
|
||||
{
|
||||
assert(objects.count(ID));
|
||||
assert(objects.at(ID)->objects.count(subID));
|
||||
objects.at(ID)->objects.erase(subID);
|
||||
assert(objects.at(ID)->subObjects.count(subID));
|
||||
objects.at(ID)->subObjects.erase(subID); //TODO: cleanup string id map
|
||||
}
|
||||
|
||||
std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const
|
||||
@@ -246,14 +245,28 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype)
|
||||
{
|
||||
if (objects.count(type))
|
||||
{
|
||||
if (objects.at(type)->objects.count(subtype))
|
||||
return objects.at(type)->objects.at(subtype);
|
||||
if (objects.at(type)->subObjects.count(subtype))
|
||||
return objects.at(type)->subObjects.at(subtype);
|
||||
}
|
||||
logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype;
|
||||
assert(0); // FIXME: throw error?
|
||||
throw std::runtime_error("Object type handler not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string type, std::string subtype) const
|
||||
{
|
||||
boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("core", "object", type, false);
|
||||
if(id)
|
||||
{
|
||||
si32 subId = objects.at(id.get())->subIds.at(subtype);
|
||||
return objects.at(id.get())->subObjects.at(subId);
|
||||
}
|
||||
logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype;
|
||||
throw std::runtime_error("Object type handler not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
std::set<si32> CObjectClassesHandler::knownObjects() const
|
||||
{
|
||||
std::set<si32> ret;
|
||||
@@ -270,7 +283,7 @@ std::set<si32> CObjectClassesHandler::knownSubObjects(si32 primaryID) const
|
||||
|
||||
if (objects.count(primaryID))
|
||||
{
|
||||
for (auto entry : objects.at(primaryID)->objects)
|
||||
for (auto entry : objects.at(primaryID)->subObjects)
|
||||
ret.insert(entry.first);
|
||||
}
|
||||
return ret;
|
||||
@@ -292,7 +305,7 @@ void CObjectClassesHandler::afterLoadFinalization()
|
||||
{
|
||||
for (auto entry : objects)
|
||||
{
|
||||
for (auto obj : entry.second->objects)
|
||||
for (auto obj : entry.second->subObjects)
|
||||
{
|
||||
obj.second->afterLoadFinalization();
|
||||
if (obj.second->getTemplates().empty())
|
||||
@@ -331,6 +344,12 @@ void AObjectTypeHandler::setType(si32 type, si32 subtype)
|
||||
this->subtype = subtype;
|
||||
}
|
||||
|
||||
void AObjectTypeHandler::setTypeName(std::string type, std::string subtype)
|
||||
{
|
||||
this->typeName = type;
|
||||
this->subTypeName = subtype;
|
||||
}
|
||||
|
||||
static ui32 loadJsonOrMax(const JsonNode & input)
|
||||
{
|
||||
if (input.isNull())
|
||||
@@ -377,6 +396,14 @@ bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemp
|
||||
return false; // by default there are no overrides
|
||||
}
|
||||
|
||||
void AObjectTypeHandler::preInitObject(CGObjectInstance * obj) const
|
||||
{
|
||||
obj->ID = Obj(type);
|
||||
obj->subID = subtype;
|
||||
obj->typeName = typeName;
|
||||
obj->subTypeName = subTypeName;
|
||||
}
|
||||
|
||||
void AObjectTypeHandler::initTypeData(const JsonNode & input)
|
||||
{
|
||||
// empty implementation for overrides
|
||||
|
@@ -104,11 +104,14 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
|
||||
si32 type;
|
||||
si32 subtype;
|
||||
|
||||
std::string typeName;
|
||||
std::string subTypeName;
|
||||
|
||||
JsonNode base; /// describes base template
|
||||
|
||||
std::vector<ObjectTemplate> templates;
|
||||
protected:
|
||||
|
||||
void preInitObject(CGObjectInstance * obj) const;
|
||||
virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
|
||||
|
||||
/// initialization for classes that inherit this one
|
||||
@@ -117,6 +120,7 @@ public:
|
||||
virtual ~AObjectTypeHandler(){}
|
||||
|
||||
void setType(si32 type, si32 subtype);
|
||||
void setTypeName(std::string type, std::string subtype);
|
||||
|
||||
/// loads generic data from Json structure and passes it towards type-specific constructors
|
||||
void init(const JsonNode & input, boost::optional<std::string> name = boost::optional<std::string>());
|
||||
@@ -149,12 +153,16 @@ public:
|
||||
/// This should set remaining properties, including randomized or depending on map
|
||||
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0;
|
||||
|
||||
/// Returns object configuration, if available. Othervice returns NULL
|
||||
/// Returns object configuration, if available. Otherwise returns NULL
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const = 0;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & type & subtype & templates & rmgInfo & objectName;
|
||||
if(version >= 755)
|
||||
{
|
||||
h & typeName & subTypeName;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -167,16 +175,21 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase
|
||||
struct ObjectContainter
|
||||
{
|
||||
si32 id;
|
||||
|
||||
std::string identifier;
|
||||
std::string name; // human-readable name
|
||||
std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map
|
||||
std::string handlerName; // ID of handler that controls this object, should be determined using handlerConstructor map
|
||||
|
||||
JsonNode base;
|
||||
std::map<si32, TObjectTypeHandler> objects;
|
||||
std::map<si32, TObjectTypeHandler> subObjects;
|
||||
std::map<std::string, si32> subIds;//full id from core scope -> subtype
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & name & handlerName & base & objects;
|
||||
h & name & handlerName & base & subObjects;
|
||||
if(version >= 755)
|
||||
{
|
||||
h & identifier & subIds;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -194,8 +207,8 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase
|
||||
/// format: customNames[primaryID][secondaryID] -> name
|
||||
std::map<si32, std::vector<std::string>> customNames;
|
||||
|
||||
void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj);
|
||||
ObjectContainter * loadFromJson(const JsonNode & json);
|
||||
void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj);
|
||||
ObjectContainter * loadFromJson(const JsonNode & json, const std::string & name);
|
||||
public:
|
||||
CObjectClassesHandler();
|
||||
|
||||
@@ -204,7 +217,7 @@ public:
|
||||
void loadObject(std::string scope, std::string name, const JsonNode & data) override;
|
||||
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
|
||||
|
||||
void loadSubObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>());
|
||||
void loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>());
|
||||
void removeSubObject(si32 ID, si32 subID);
|
||||
|
||||
void beforeValidate(JsonNode & object) override;
|
||||
@@ -218,6 +231,7 @@ public:
|
||||
|
||||
/// returns handler for specified object (ID-based). ObjectHandler keeps ownership
|
||||
TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const;
|
||||
TObjectTypeHandler getHandlerFor(std::string type, std::string subtype) const;
|
||||
|
||||
std::string getObjectName(si32 type) const;
|
||||
std::string getObjectName(si32 type, si32 subtype) const;
|
||||
|
@@ -326,7 +326,14 @@ bool CGObjectInstance::passableFor(PlayerColor color) const
|
||||
|
||||
void CGObjectInstance::writeJson(JsonNode & json, bool withState) const
|
||||
{
|
||||
logGlobal->debugStream() <<"Save: [" << pos << "] " << id << " " << ID << " " << subID << " " << typeName << " " << subTypeName;
|
||||
|
||||
json.setType(JsonNode::DATA_STRUCT);
|
||||
json["type"].String() = typeName;
|
||||
json["subType"].String() = subTypeName;
|
||||
json["x"].Float() = pos.x;
|
||||
json["y"].Float() = pos.y;
|
||||
json["l"].Float() = pos.z;
|
||||
|
||||
appearance.writeJson(json["template"]);
|
||||
writeJsonOptions(json["options"]);
|
||||
@@ -341,10 +348,16 @@ void CGObjectInstance::readJson(const JsonNode & json, bool withState)
|
||||
logGlobal->error("Invalid object instance data");
|
||||
return;
|
||||
}
|
||||
pos.x = json["x"].Float();
|
||||
pos.y = json["y"].Float();
|
||||
pos.z = json["l"].Float();
|
||||
|
||||
appearance.readJson(json["template"]);
|
||||
readJsonOptions(json["options"]);
|
||||
if(withState)
|
||||
readJsonState(json["state"]);
|
||||
|
||||
logGlobal->debugStream() <<"Load: [" << pos << "] " << id << " " << ID << " " << subID << " " << typeName << " " << subTypeName;
|
||||
}
|
||||
|
||||
void CGObjectInstance::writeJsonOptions(JsonNode & json) const
|
||||
|
@@ -113,6 +113,9 @@ public:
|
||||
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
|
||||
bool blockVisit;
|
||||
|
||||
std::string typeName;
|
||||
std::string subTypeName;
|
||||
|
||||
CGObjectInstance();
|
||||
~CGObjectInstance();
|
||||
|
||||
@@ -171,6 +174,11 @@ public:
|
||||
{
|
||||
h & pos & ID & subID & id & tempOwner & blockVisit & appearance;
|
||||
//definfo is handled by map serializer
|
||||
|
||||
if(version >= 755)
|
||||
{
|
||||
h & typeName & subTypeName;
|
||||
}
|
||||
}
|
||||
|
||||
///Entry point of Json serialization
|
||||
|
@@ -188,6 +188,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config)
|
||||
CGObjectInstance * CRewardableConstructor::create(ObjectTemplate tmpl) const
|
||||
{
|
||||
auto ret = new CRewardableObject();
|
||||
preInitObject(ret);
|
||||
ret->appearance = tmpl;
|
||||
return ret;
|
||||
}
|
||||
|
@@ -31,8 +31,7 @@ protected:
|
||||
ObjectType * createTyped(ObjectTemplate tmpl) const
|
||||
{
|
||||
auto obj = new ObjectType();
|
||||
obj->ID = tmpl.id;
|
||||
obj->subID = tmpl.subid;
|
||||
preInitObject(obj);
|
||||
obj->appearance = tmpl;
|
||||
return obj;
|
||||
}
|
||||
|
@@ -284,6 +284,13 @@ void CMapLoaderJson::readMap()
|
||||
map->initTerrain();
|
||||
readTerrain();
|
||||
readObjects();
|
||||
|
||||
// Calculate blocked / visitable positions
|
||||
for(auto & elem : map->objects)
|
||||
{
|
||||
map->addBlockVisTiles(elem);
|
||||
}
|
||||
map->calculateGuardingGreaturePositions();
|
||||
}
|
||||
|
||||
void CMapLoaderJson::readHeader()
|
||||
@@ -569,6 +576,7 @@ CMapLoaderJson::MapObjectLoader::MapObjectLoader(CMapLoaderJson * _owner, const
|
||||
|
||||
void CMapLoaderJson::MapObjectLoader::construct()
|
||||
{
|
||||
//TODO:consider move to ObjectTypeHandler
|
||||
//find type handler
|
||||
std::string typeName = configuration["type"].String(), subTypeName = configuration["subType"].String();
|
||||
if(typeName.empty())
|
||||
@@ -584,13 +592,16 @@ void CMapLoaderJson::MapObjectLoader::construct()
|
||||
|
||||
si32 type = owner->getIdentifier("object", typeName);
|
||||
|
||||
// VLC->objtypeh->getHandlerFor()
|
||||
//TODO:MapObjectLoader::construct()
|
||||
handler = VLC->objtypeh->getHandlerFor(typeName, subTypeName);
|
||||
|
||||
instance = handler->create(ObjectTemplate());
|
||||
instance->id = ObjectInstanceID(owner->map->objects.size());
|
||||
owner->map->objects.push_back(instance);
|
||||
}
|
||||
|
||||
void CMapLoaderJson::MapObjectLoader::configure()
|
||||
{
|
||||
//TODO:MapObjectLoader::configure()
|
||||
instance->readJson(configuration, false);
|
||||
}
|
||||
|
||||
void CMapLoaderJson::readObjects()
|
||||
|
@@ -563,11 +563,10 @@ void CMapGenerator::createConnections()
|
||||
}
|
||||
if (!guardPos.valid())
|
||||
{
|
||||
auto teleport1 = new CGMonolith;
|
||||
teleport1->ID = Obj::MONOLITH_TWO_WAY;
|
||||
teleport1->subID = getNextMonlithIndex();
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, getNextMonlithIndex());
|
||||
auto teleport1 = factory->create(ObjectTemplate());
|
||||
|
||||
auto teleport2 = new CGMonolith(*teleport1);
|
||||
auto teleport2 = factory->create(ObjectTemplate());
|
||||
|
||||
zoneA->addRequiredObject (teleport1, connection.getGuardStrength());
|
||||
zoneB->addRequiredObject (teleport2, connection.getGuardStrength());
|
||||
|
@@ -1031,10 +1031,9 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
|
||||
amount = strength / VLC->creh->creatures[creId]->AIValue;
|
||||
}
|
||||
|
||||
auto guardFactory = VLC->objtypeh->getHandlerFor(Obj::MONSTER, creId);
|
||||
|
||||
auto guard = new CGCreature();
|
||||
guard->ID = Obj::MONSTER;
|
||||
guard->subID = creId;
|
||||
auto guard = (CGCreature *) guardFactory->create(ObjectTemplate());
|
||||
guard->character = CGCreature::HOSTILE;
|
||||
auto hlp = new CStackInstance(creId, amount);
|
||||
//will be set during initialization
|
||||
@@ -1313,18 +1312,22 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auto town = new CGTownInstance();
|
||||
town->ID = Obj::TOWN;
|
||||
si32 subType = townType;
|
||||
|
||||
if (this->townsAreSameType)
|
||||
town->subID = townType;
|
||||
else
|
||||
if(totalTowns>0)
|
||||
{
|
||||
if(!this->townsAreSameType)
|
||||
{
|
||||
if (townTypes.size())
|
||||
town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
||||
subType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
|
||||
else
|
||||
town->subID = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed
|
||||
subType = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed
|
||||
}
|
||||
}
|
||||
|
||||
auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, subType);
|
||||
auto town = (CGTownInstance *) townFactory->create(ObjectTemplate());
|
||||
town->ID = Obj::TOWN;
|
||||
|
||||
town->tempOwner = player;
|
||||
if (hasFort)
|
||||
@@ -1337,10 +1340,8 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
|
||||
town->possibleSpells.push_back(spell->id);
|
||||
}
|
||||
|
||||
if (!totalTowns)
|
||||
if (totalTowns <= 0)
|
||||
{
|
||||
//first town in zone sets the facton of entire zone
|
||||
town->subID = townType;
|
||||
//register MAIN town of zone
|
||||
gen->registerZone(town->subID);
|
||||
//first town in zone goes in the middle
|
||||
@@ -1376,10 +1377,9 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen)
|
||||
randomizeTownType(gen);
|
||||
}
|
||||
|
||||
auto town = new CGTownInstance();
|
||||
town->ID = Obj::TOWN;
|
||||
auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, townType);
|
||||
|
||||
town->subID = townType;
|
||||
CGTownInstance * town = (CGTownInstance *) townFactory->create(ObjectTemplate());
|
||||
town->tempOwner = player;
|
||||
town->builtBuildings.insert(BuildingID::FORT);
|
||||
town->builtBuildings.insert(BuildingID::DEFAULT);
|
||||
@@ -1490,20 +1490,25 @@ void CRmgTemplateZone::paintZoneTerrain (CMapGenerator* gen, ETerrainType terrai
|
||||
|
||||
bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
|
||||
{
|
||||
std::vector<Res::ERes> required_mines;
|
||||
required_mines.push_back(Res::ERes::WOOD);
|
||||
required_mines.push_back(Res::ERes::ORE);
|
||||
|
||||
static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE};
|
||||
static const Res::ERes preciousResources[] = {Res::ERes::GEMS, Res::ERes::CRYSTAL, Res::ERes::MERCURY, Res::ERes::SULFUR};
|
||||
|
||||
std::array<TObjectTypeHandler, 7> factory =
|
||||
{
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 0),
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 1),
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 2),
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 3),
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 4),
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 5),
|
||||
VLC->objtypeh->getHandlerFor(Obj::MINE, 6)
|
||||
};
|
||||
|
||||
for (const auto & res : woodOre)
|
||||
{
|
||||
for (int i = 0; i < mines[res]; i++)
|
||||
{
|
||||
auto mine = new CGMine();
|
||||
mine->ID = Obj::MINE;
|
||||
mine->subID = static_cast<si32>(res);
|
||||
auto mine = (CGMine *) factory.at(static_cast<si32>(res))->create(ObjectTemplate());
|
||||
mine->producedResource = res;
|
||||
mine->producedQuantity = mine->defaultResProduction();
|
||||
if (!i)
|
||||
@@ -1516,9 +1521,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
|
||||
{
|
||||
for (int i = 0; i < mines[res]; i++)
|
||||
{
|
||||
auto mine = new CGMine();
|
||||
mine->ID = Obj::MINE;
|
||||
mine->subID = static_cast<si32>(res);
|
||||
auto mine = (CGMine *) factory.at(static_cast<si32>(res))->create(ObjectTemplate());
|
||||
mine->producedResource = res;
|
||||
mine->producedQuantity = mine->defaultResProduction();
|
||||
addRequiredObject(mine, 3500);
|
||||
@@ -1526,9 +1529,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
|
||||
}
|
||||
for (int i = 0; i < mines[Res::GOLD]; i++)
|
||||
{
|
||||
auto mine = new CGMine();
|
||||
mine->ID = Obj::MINE;
|
||||
mine->subID = static_cast<si32>(Res::GOLD);
|
||||
auto mine = (CGMine *) factory.at(Res::GOLD)->create(ObjectTemplate());
|
||||
mine->producedResource = Res::GOLD;
|
||||
mine->producedQuantity = mine->defaultResProduction();
|
||||
addRequiredObject(mine, 7000);
|
||||
@@ -2107,9 +2108,8 @@ void CRmgTemplateZone::placeAndGuardObject(CMapGenerator* gen, CGObjectInstance*
|
||||
|
||||
void CRmgTemplateZone::placeSubterraneanGate(CMapGenerator* gen, int3 pos, si32 guardStrength)
|
||||
{
|
||||
auto gate = new CGSubterraneanGate;
|
||||
gate->ID = Obj::SUBTERRANEAN_GATE;
|
||||
gate->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SUBTERRANEAN_GATE, 0);
|
||||
auto gate = factory->create(ObjectTemplate());
|
||||
placeObject (gen, gate, pos, true);
|
||||
addToConnectLater (getAccessibleOffset (gen, gate->appearance, pos)); //guard will be placed on accessibleOffset
|
||||
guardObject (gen, gate, guardStrength, true);
|
||||
@@ -2303,9 +2303,8 @@ ObjectInfo CRmgTemplateZone::getRandomObject(CMapGenerator* gen, CTreasurePileIn
|
||||
{
|
||||
oi.generateObject = [minValue]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
obj->resources[Res::GOLD] = minValue;
|
||||
return obj;
|
||||
};
|
||||
@@ -2393,9 +2392,6 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
{
|
||||
oi.generateObject = [i, gen, this]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGHeroInstance;
|
||||
obj->ID = Obj::PRISON;
|
||||
|
||||
std::vector<ui32> possibleHeroes;
|
||||
for (int j = 0; j < gen->map->allowedHeroes.size(); j++)
|
||||
{
|
||||
@@ -2404,6 +2400,10 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
}
|
||||
|
||||
auto hid = *RandomGeneratorUtil::nextItem(possibleHeroes, gen->rand);
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
|
||||
auto obj = (CGHeroInstance *) factory->create(ObjectTemplate());
|
||||
|
||||
|
||||
obj->subID = hid; //will be initialized later
|
||||
obj->exp = prisonExp[i];
|
||||
obj->setOwner(PlayerColor::NEUTRAL);
|
||||
@@ -2471,9 +2471,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
{
|
||||
oi.generateObject = [i, gen]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGArtifact();
|
||||
obj->ID = Obj::SPELL_SCROLL;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SPELL_SCROLL, 0);
|
||||
auto obj = (CGArtifact *) factory->create(ObjectTemplate());
|
||||
std::vector<SpellID> out;
|
||||
|
||||
for (auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
|
||||
@@ -2499,9 +2498,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
{
|
||||
oi.generateObject = [i]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
obj->resources[Res::GOLD] = i * 5000;
|
||||
return obj;
|
||||
};
|
||||
@@ -2516,9 +2514,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
{
|
||||
oi.generateObject = [i]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
obj->gainedExp = i * 5000;
|
||||
return obj;
|
||||
};
|
||||
@@ -2564,9 +2561,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
|
||||
oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto stack = new CStackInstance(creature, creaturesAmount);
|
||||
obj->creatures.putStack(SlotID(0), stack);
|
||||
return obj;
|
||||
@@ -2582,9 +2578,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
{
|
||||
oi.generateObject = [i, gen]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
|
||||
std::vector <CSpell *> spells;
|
||||
for (auto spell : VLC->spellh->objects)
|
||||
@@ -2612,9 +2607,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
{
|
||||
oi.generateObject = [i,gen]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
|
||||
std::vector <CSpell *> spells;
|
||||
for (auto spell : VLC->spellh->objects)
|
||||
@@ -2642,9 +2636,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
|
||||
oi.generateObject = [gen]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGPandoraBox();
|
||||
obj->ID = Obj::PANDORAS_BOX;
|
||||
obj->subID = 0;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
|
||||
std::vector <CSpell *> spells;
|
||||
for (auto spell : VLC->spellh->objects)
|
||||
@@ -2716,9 +2709,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
|
||||
oi.generateObject = [creature, creaturesAmount, randomAppearance, gen, this, generateArtInfo]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGSeerHut();
|
||||
obj->ID = Obj::SEER_HUT;
|
||||
obj->subID = randomAppearance;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
|
||||
obj->rewardType = CGSeerHut::CREATURE;
|
||||
obj->rID = creature->idNumber;
|
||||
obj->rVal = creaturesAmount;
|
||||
@@ -2752,9 +2744,9 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
|
||||
oi.generateObject = [i, randomAppearance, gen, this, generateArtInfo]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGSeerHut();
|
||||
obj->ID = Obj::SEER_HUT;
|
||||
obj->subID = randomAppearance;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
|
||||
|
||||
obj->rewardType = CGSeerHut::EXPERIENCE;
|
||||
obj->rID = 0; //unitialized?
|
||||
obj->rVal = seerExpGold[i];
|
||||
@@ -2774,9 +2766,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
|
||||
oi.generateObject = [i, randomAppearance, gen, this, generateArtInfo]() -> CGObjectInstance *
|
||||
{
|
||||
auto obj = new CGSeerHut();
|
||||
obj->ID = Obj::SEER_HUT;
|
||||
obj->subID = randomAppearance;
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
|
||||
obj->rewardType = CGSeerHut::RESOURCES;
|
||||
obj->rID = Res::GOLD;
|
||||
obj->rVal = seerExpGold[i];
|
||||
|
@@ -152,6 +152,12 @@ void MapComparer::compareObject(const CGObjectInstance * actual, const CGObjectI
|
||||
{
|
||||
BOOST_CHECK_EQUAL(actual->getStringId(), expected->getStringId());
|
||||
BOOST_CHECK_EQUAL(typeid(actual).name(), typeid(expected).name());//todo: remove and use just comparison
|
||||
|
||||
std::string actualFullID = boost::to_string(boost::format("%s(%d)|%s(%d)") % actual->typeName % actual->id % actual->subTypeName % actual->subID);
|
||||
std::string expectedFullID = boost::to_string(boost::format("%s(%d)|%s(%d)") % expected->typeName % expected->id % expected->subTypeName % expected->subID);
|
||||
|
||||
BOOST_CHECK_EQUAL(actualFullID, expectedFullID);
|
||||
BOOST_CHECK_EQUAL(actual->pos, expected->pos);
|
||||
}
|
||||
|
||||
void MapComparer::compareObjects()
|
||||
|
Reference in New Issue
Block a user