// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2008 Marti�o Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "unit_type.h" #include #include "util.h" #include "upgrade_type.h" #include "resource_type.h" #include "sound.h" #include "logger.h" #include "xml_parser.h" #include "tech_tree.h" #include "resource.h" #include "renderer.h" #include "game_util.h" #include "leak_dumper.h" #include "unit_particle_type.h" using namespace Shared::Xml; using namespace Shared::Graphics; using namespace Shared::Util; namespace Glest{ namespace Game{ // =============================== // class Level // =============================== void Level::init(string name, int kills){ this->name= name; this->kills= kills; } // ===================================================== // class UnitType // ===================================================== // ===================== PUBLIC ======================== const char *UnitType::propertyNames[]= {"burnable", "rotated_climb"}; // ==================== creation and loading ==================== UnitType::UnitType(){ lightColor= Vec3f(0.f); light= false; multiSelect= false; armorType= NULL; for(int i=0; iid= id; try{ Logger::getInstance().add("Unit type: " + formatString(name), true); //file load checksum->addFile(path); XmlTree xmlTree; xmlTree.load(path); const XmlNode *unitNode= xmlTree.getRootNode(); const XmlNode *parametersNode= unitNode->getChild("parameters"); //size size= parametersNode->getChild("size")->getAttribute("value")->getIntValue(); //height height= parametersNode->getChild("height")->getAttribute("value")->getIntValue(); //maxHp maxHp= parametersNode->getChild("max-hp")->getAttribute("value")->getIntValue(); //hpRegeneration hpRegeneration= parametersNode->getChild("max-hp")->getAttribute("regeneration")->getIntValue(); //maxEp maxEp= parametersNode->getChild("max-ep")->getAttribute("value")->getIntValue(); if(maxEp!=0){ //wpRegeneration epRegeneration= parametersNode->getChild("max-ep")->getAttribute("regeneration")->getIntValue(); } //armor armor= parametersNode->getChild("armor")->getAttribute("value")->getIntValue(); //armor type string string armorTypeName= parametersNode->getChild("armor-type")->getAttribute("value")->getRestrictedValue(); armorType= techTree->getArmorType(armorTypeName); //sight sight= parametersNode->getChild("sight")->getAttribute("value")->getIntValue(); //prod time productionTime= parametersNode->getChild("time")->getAttribute("value")->getIntValue(); //multi selection multiSelect= parametersNode->getChild("multi-selection")->getAttribute("value")->getBoolValue(); //cellmap const XmlNode *cellMapNode= parametersNode->getChild("cellmap"); bool hasCellMap= cellMapNode->getAttribute("value")->getBoolValue(); if(hasCellMap){ cellMap= new bool[size*size]; for(int i=0; igetChild("row", i); string row= rowNode->getAttribute("value")->getRestrictedValue(); if(row.size()!=size){ throw runtime_error("Cellmap row has not the same length as unit size"); } for(int j=0; jgetChild("levels"); levels.resize(levelsNode->getChildCount()); for(int i=0; igetChild("level", i); levels[i].init( levelNode->getAttribute("name")->getRestrictedValue(), levelNode->getAttribute("kills")->getIntValue()); } //fields const XmlNode *fieldsNode= parametersNode->getChild("fields"); for(int i=0; igetChildCount(); ++i){ const XmlNode *fieldNode= fieldsNode->getChild("field", i); string fieldName= fieldNode->getAttribute("value")->getRestrictedValue(); if(fieldName=="land"){ fields[fLand]= true; } else if(fieldName=="air"){ fields[fAir]= true; } else{ throw runtime_error("Not a valid field: "+fieldName+": "+ path); } } //properties const XmlNode *propertiesNode= parametersNode->getChild("properties"); for(int i=0; igetChildCount(); ++i){ const XmlNode *propertyNode= propertiesNode->getChild("property", i); string propertyName= propertyNode->getAttribute("value")->getRestrictedValue(); bool found= false; for(int i=0; ihasChild("damage-particles")){ const XmlNode *particleNode= parametersNode->getChild("damage-particles"); bool particleEnabled= particleNode->getAttribute("value")->getBoolValue(); if(particleEnabled){ for(int i=0; igetChildCount(); ++i){ const XmlNode *particleFileNode= particleNode->getChild("particle-file", i); string path= particleFileNode->getAttribute("path")->getRestrictedValue(); UnitParticleSystemType *unitParticleSystemType= new UnitParticleSystemType(); unitParticleSystemType->load(dir, dir + "/" + path, Renderer::getInstance().newTexture2D(rsGame)); damageParticleSystemTypes.push_back(unitParticleSystemType); } } } //light const XmlNode *lightNode= parametersNode->getChild("light"); light= lightNode->getAttribute("enabled")->getBoolValue(); if(light){ lightColor.x= lightNode->getAttribute("red")->getFloatValue(0.f, 1.f); lightColor.y= lightNode->getAttribute("green")->getFloatValue(0.f, 1.f); lightColor.z= lightNode->getAttribute("blue")->getFloatValue(0.f, 1.f); } //rotationAllowed if(parametersNode->hasChild("rotationAllowed")){ const XmlNode *rotationAllowedNode= parametersNode->getChild("rotationAllowed"); rotationAllowed= rotationAllowedNode->getAttribute("value")->getBoolValue(); } else { rotationAllowed=true; } //unit requirements const XmlNode *unitRequirementsNode= parametersNode->getChild("unit-requirements"); for(int i=0; igetChildCount(); ++i){ const XmlNode *unitNode= unitRequirementsNode->getChild("unit", i); string name= unitNode->getAttribute("name")->getRestrictedValue(); unitReqs.push_back(factionType->getUnitType(name)); } //upgrade requirements const XmlNode *upgradeRequirementsNode= parametersNode->getChild("upgrade-requirements"); for(int i=0; igetChildCount(); ++i){ const XmlNode *upgradeReqNode= upgradeRequirementsNode->getChild("upgrade", i); string name= upgradeReqNode->getAttribute("name")->getRestrictedValue(); upgradeReqs.push_back(factionType->getUpgradeType(name)); } //resource requirements const XmlNode *resourceRequirementsNode= parametersNode->getChild("resource-requirements"); costs.resize(resourceRequirementsNode->getChildCount()); for(int i=0; igetChild("resource", i); string name= resourceNode->getAttribute("name")->getRestrictedValue(); int amount= resourceNode->getAttribute("amount")->getIntValue(); costs[i].init(techTree->getResourceType(name), amount); } //resources stored const XmlNode *resourcesStoredNode= parametersNode->getChild("resources-stored"); storedResources.resize(resourcesStoredNode->getChildCount()); for(int i=0; igetChild("resource", i); string name= resourceNode->getAttribute("name")->getRestrictedValue(); int amount= resourceNode->getAttribute("amount")->getIntValue(); storedResources[i].init(techTree->getResourceType(name), amount); } //image const XmlNode *imageNode= parametersNode->getChild("image"); image= Renderer::getInstance().newTexture2D(rsGame); image->load(dir+"/"+imageNode->getAttribute("path")->getRestrictedValue()); //image cancel const XmlNode *imageCancelNode= parametersNode->getChild("image-cancel"); cancelImage= Renderer::getInstance().newTexture2D(rsGame); cancelImage->load(dir+"/"+imageCancelNode->getAttribute("path")->getRestrictedValue()); //meeting point const XmlNode *meetingPointNode= parametersNode->getChild("meeting-point"); meetingPoint= meetingPointNode->getAttribute("value")->getBoolValue(); if(meetingPoint){ meetingPointImage= Renderer::getInstance().newTexture2D(rsGame); meetingPointImage->load(dir+"/"+meetingPointNode->getAttribute("image-path")->getRestrictedValue()); } //selection sounds const XmlNode *selectionSoundNode= parametersNode->getChild("selection-sounds"); if(selectionSoundNode->getAttribute("enabled")->getBoolValue()){ selectionSounds.resize(selectionSoundNode->getChildCount()); for(int i=0; igetChild("sound", i); string path= soundNode->getAttribute("path")->getRestrictedValue(); StaticSound *sound= new StaticSound(); sound->load(dir + "/" + path); selectionSounds[i]= sound; } } //command sounds const XmlNode *commandSoundNode= parametersNode->getChild("command-sounds"); if(commandSoundNode->getAttribute("enabled")->getBoolValue()){ commandSounds.resize(commandSoundNode->getChildCount()); for(int i=0; igetChildCount(); ++i){ const XmlNode *soundNode= commandSoundNode->getChild("sound", i); string path= soundNode->getAttribute("path")->getRestrictedValue(); StaticSound *sound= new StaticSound(); sound->load(dir + "/" + path); commandSounds[i]= sound; } } //skills const XmlNode *skillsNode= unitNode->getChild("skills"); skillTypes.resize(skillsNode->getChildCount()); for(int i=0; igetChild("skill", i); const XmlNode *typeNode= sn->getChild("type"); string classId= typeNode->getAttribute("value")->getRestrictedValue(); SkillType *skillType= SkillTypeFactory::getInstance().newInstance(classId); skillType->load(sn, dir, techTree, factionType); skillTypes[i]= skillType; } //commands const XmlNode *commandsNode= unitNode->getChild("commands"); commandTypes.resize(commandsNode->getChildCount()); for(int i=0; igetChild("command", i); const XmlNode *typeNode= commandNode->getChild("type"); string classId= typeNode->getAttribute("value")->getRestrictedValue(); CommandType *commandType= CommandTypeFactory::getInstance().newInstance(classId); commandType->load(i, commandNode, dir, techTree, factionType, *this); commandTypes[i]= commandType; } computeFirstStOfClass(); computeFirstCtOfClass(); if(getFirstStOfClass(scStop)==NULL){ throw runtime_error("Every unit must have at least one stop skill: "+ path); } if(getFirstStOfClass(scDie)==NULL){ throw runtime_error("Every unit must have at least one die skill: "+ path); } } //Exception handling (conversions and so on); catch(const exception &e){ throw runtime_error("Error loading UnitType: " + path + "\n" + e.what()); } SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } // ==================== get ==================== const CommandType *UnitType::getFirstCtOfClass(CommandClass commandClass) const{ //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(firstCommandTypeOfClass[commandClass] == NULL) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] commandClass = %d\n",__FILE__,__FUNCTION__,__LINE__,commandClass); /* for(int j=0; jgetClass()== CommandClass(j)){ return commandTypes[i]; } } } */ SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } return firstCommandTypeOfClass[commandClass]; } const SkillType *UnitType::getFirstStOfClass(SkillClass skillClass) const{ if(firstSkillTypeOfClass[skillClass] == NULL) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] skillClass = %d\n",__FILE__,__FUNCTION__,__LINE__,skillClass); /* for(int j= 0; jgetClass()== SkillClass(j)){ return skillTypes[i]; } } } */ //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } return firstSkillTypeOfClass[skillClass]; } const HarvestCommandType *UnitType::getFirstHarvestCommand(const ResourceType *resourceType) const{ for(int i=0; igetClass()== ccHarvest){ const HarvestCommandType *hct= static_cast(commandTypes[i]); if(hct->canHarvest(resourceType)){ return hct; } } } return NULL; } const AttackCommandType *UnitType::getFirstAttackCommand(Field field) const{ for(int i=0; igetClass()== ccAttack){ const AttackCommandType *act= static_cast(commandTypes[i]); if(act->getAttackSkillType()->getAttackField(field)){ return act; } } } return NULL; } const RepairCommandType *UnitType::getFirstRepairCommand(const UnitType *repaired) const{ for(int i=0; igetClass()== ccRepair){ const RepairCommandType *rct= static_cast(commandTypes[i]); if(rct->isRepairableUnitType(repaired)){ return rct; } } } return NULL; } bool UnitType::getCellMapCell(int x, int y, CardinalDir facing) const { assert(cellMap); int tmp; switch (facing) { case CardinalDir::EAST: tmp = y; y = x; x = size - tmp - 1; break; case CardinalDir::SOUTH: x = size - x - 1; y = size - y - 1; break; case CardinalDir::WEST: tmp = x; x = y; y = size - tmp - 1; break; default: break; } return cellMap[y * size + x]; } int UnitType::getStore(const ResourceType *rt) const{ for(int i=0; igetName()==skillName){ if(skillTypes[i]->getClass()==skillClass){ return skillTypes[i]; } else{ throw runtime_error("Skill \""+skillName+"\" is not of class \""+SkillType::skillClassToStr(skillClass)); } } } throw runtime_error("No skill named \""+skillName+"\""); } // ==================== totals ==================== int UnitType::getTotalMaxHp(const TotalUpgrade *totalUpgrade) const{ return maxHp + totalUpgrade->getMaxHp(); } int UnitType::getTotalMaxEp(const TotalUpgrade *totalUpgrade) const{ return maxEp + totalUpgrade->getMaxEp(); } int UnitType::getTotalArmor(const TotalUpgrade *totalUpgrade) const{ return armor + totalUpgrade->getArmor(); } int UnitType::getTotalSight(const TotalUpgrade *totalUpgrade) const{ return sight + totalUpgrade->getSight(); } // ==================== has ==================== bool UnitType::hasSkillClass(SkillClass skillClass) const{ return firstSkillTypeOfClass[skillClass]!=NULL; } bool UnitType::hasCommandType(const CommandType *commandType) const{ assert(commandType!=NULL); for(int i=0; igetClass()== SkillClass(j)){ firstSkillTypeOfClass[j]= skillTypes[i]; break; } } } } void UnitType::computeFirstCtOfClass(){ SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] \n",__FILE__,__FUNCTION__,__LINE__); for(int j=0; jgetClass()== CommandClass(j)){ firstCommandTypeOfClass[j]= commandTypes[i]; break; } } } } const CommandType* UnitType::findCommandTypeById(int id) const{ for(int i=0; igetId()==id){ return commandType; } } return NULL; } string UnitType::getCommandTypeListDesc() const { string desc = "Commands: "; for(int i=0; igetId()); + " toString: " + commandType->toString(); } return desc; } std::string UnitType::toString() const { std::string result = ""; result = "Unit Name: [" + name + "] id = " + intToStr(id); result += " maxHp = " + intToStr(maxHp); result += " hpRegeneration = " + intToStr(hpRegeneration); result += " maxEp = " + intToStr(maxEp); result += " epRegeneration = " + intToStr(epRegeneration); for(int i = 0; i < fieldCount; i++) { result += " fields index = " + intToStr(i) + " value = " + intToStr(fields[i]); } for(int i = 0; i < pCount; i++) { result += " properties index = " + intToStr(i) + " value = " + intToStr(properties[i]); } result += " armor = " + intToStr(armor); if(armorType != NULL) { result += " armorType Name: [" + armorType->getName() + " id = " + intToStr(armorType->getId()); } result += " light = " + intToStr(light); result += " lightColor = " + lightColor.getString(); result += " multiSelect = " + intToStr(multiSelect); result += " sight = " + intToStr(sight); result += " size = " + intToStr(size); result += " height = " + intToStr(height); result += " rotatedBuildPos = " + floatToStr(rotatedBuildPos); result += " rotationAllowed = " + intToStr(rotationAllowed); if(cellMap != NULL) { result += " cellMap:"; for(int i = 0; i < size; ++i) { for(int j = 0; j < size; ++j){ result += " i = " + intToStr(i) + " j = " + intToStr(j) + " value = " + intToStr(cellMap[i*size+j]); } } } result += " skillTypes:"; for(int i = 0; i < skillTypes.size(); ++i) { result += " i = " + intToStr(i) + " " + skillTypes[i]->toString(); } result += " commandTypes:"; for(int i = 0; i < commandTypes.size(); ++i) { result += " i = " + intToStr(i) + " " + commandTypes[i]->toString(); } result += " storedResources:"; for(int i = 0; i < storedResources.size(); ++i) { result += " i = " + intToStr(i) + " " + storedResources[i].getDescription(); } result += " levels:"; for(int i = 0; i < levels.size(); ++i) { result += " i = " + intToStr(i) + " " + levels[i].getName(); } result += " meetingPoint = " + intToStr(meetingPoint); return result; } }}//end namespace