1453 lines
52 KiB
C++
1453 lines
52 KiB
C++
// ==============================================================
|
|
// 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 "skill_type.h"
|
|
|
|
#include <cassert>
|
|
#include <iterator>
|
|
|
|
#include "sound.h"
|
|
#include "util.h"
|
|
#include "lang.h"
|
|
#include "renderer.h"
|
|
#include "particle_type.h"
|
|
#include "unit_particle_type.h"
|
|
#include "projectile_type.h"
|
|
#include "tech_tree.h"
|
|
#include "faction_type.h"
|
|
#include "leak_dumper.h"
|
|
|
|
using namespace Shared::Util;
|
|
using namespace Shared::Graphics;
|
|
|
|
namespace Glest{ namespace Game{
|
|
|
|
int SkillType::nextAttackBoostId = 0;
|
|
|
|
AttackBoost::AttackBoost() : boostUpgrade() {
|
|
enabled = false;
|
|
allowMultipleBoosts = false;
|
|
radius = 0;
|
|
targetType = abtFaction;
|
|
unitParticleSystemTypeForSourceUnit = NULL;
|
|
unitParticleSystemTypeForAffectedUnit = NULL;
|
|
includeSelf = false;
|
|
}
|
|
|
|
AttackBoost::~AttackBoost() {
|
|
delete unitParticleSystemTypeForSourceUnit;
|
|
unitParticleSystemTypeForSourceUnit = NULL;
|
|
|
|
delete unitParticleSystemTypeForAffectedUnit;
|
|
unitParticleSystemTypeForAffectedUnit = NULL;
|
|
}
|
|
|
|
bool AttackBoost::isAffected(const Unit *source, const Unit *dest) const {
|
|
bool result = false;
|
|
if(enabled == true &&
|
|
source != NULL && dest != NULL &&
|
|
(includeSelf == true || source != dest)) {
|
|
bool destUnitMightApply = false;
|
|
if(source == dest && includeSelf == true) {
|
|
destUnitMightApply = true;
|
|
}
|
|
else {
|
|
// All units are affected (including enemies)
|
|
if(targetType == abtAll) {
|
|
destUnitMightApply = (boostUnitList.empty() && tags.empty());
|
|
destUnitMightApply = isInUnitListOrTags(dest->getType());
|
|
}
|
|
// Only same faction units are affected
|
|
else if(targetType == abtFaction) {
|
|
//if(boostUnitList.empty() == true) {
|
|
if(source->getFactionIndex() == dest->getFactionIndex()) {
|
|
//destUnitMightApply = true;
|
|
destUnitMightApply = (boostUnitList.empty() && tags.empty());
|
|
destUnitMightApply = isInUnitListOrTags(dest->getType());
|
|
}
|
|
//}
|
|
}
|
|
// Only ally units are affected
|
|
else if(targetType == abtAlly) {
|
|
//if(boostUnitList.empty() == true) {
|
|
if(source->isAlly(dest) == true) {
|
|
//destUnitMightApply = true;
|
|
destUnitMightApply = (boostUnitList.empty() && tags.empty());
|
|
destUnitMightApply = isInUnitListOrTags(dest->getType());
|
|
}
|
|
//}
|
|
}
|
|
// Only foe units are affected
|
|
else if(targetType == abtFoe) {
|
|
//if(boostUnitList.empty() == true) {
|
|
if(source->isAlly(dest) == false) {
|
|
//destUnitMightApply = true;
|
|
destUnitMightApply = (boostUnitList.empty() && tags.empty());
|
|
destUnitMightApply = isInUnitListOrTags(dest->getType());
|
|
}
|
|
//}
|
|
}
|
|
else if(targetType == abtUnitTypes) {
|
|
destUnitMightApply = isInUnitListOrTags(dest->getType());
|
|
}
|
|
}
|
|
|
|
if(destUnitMightApply == true) {
|
|
float distance = source->getCenteredPos().dist(dest->getCenteredPos());
|
|
if(distance <= radius) {
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool AttackBoost::isInUnitListOrTags(const UnitType *unitType) const {
|
|
// Specify which units are affected
|
|
std::set<const UnitType*>::iterator it;
|
|
for (it = boostUnitList.begin(); it != boostUnitList.end(); ++it) {
|
|
const UnitType *boostUnit = *it;
|
|
if(unitType->getId() == boostUnit->getId()) {
|
|
return true;
|
|
}
|
|
}
|
|
set<string> unitTags = unitType->getTags();
|
|
set<string> intersect;
|
|
set_intersection(tags.begin(),tags.end(),unitTags.begin(),unitTags.end(),
|
|
std::inserter(intersect,intersect.begin()));
|
|
if(!intersect.empty()) return true;
|
|
|
|
// Otherwise no match
|
|
return false;
|
|
}
|
|
|
|
string AttackBoost::getTagName(string tag, bool translatedValue) const {
|
|
if(translatedValue == false) return tag;
|
|
|
|
Lang &lang = Lang::getInstance();
|
|
return lang.getTechTreeString("TagName_" + tag, tag.c_str());
|
|
}
|
|
|
|
string AttackBoost::getDesc(bool translatedValue) const{
|
|
Lang &lang= Lang::getInstance();
|
|
string str= "";
|
|
string indent=" ";
|
|
if(enabled) {
|
|
if(boostUnitList.empty() == false) {
|
|
str+= "\n"+ lang.getString("Effects")+":\n";
|
|
}
|
|
|
|
str += indent+lang.getString("effectRadius") + ": " + intToStr(radius) +"\n";
|
|
if(allowMultipleBoosts==false) {
|
|
string allowIt=lang.getString("No");
|
|
if(allowMultipleBoosts==true)
|
|
allowIt=lang.getString("False");
|
|
str += indent+lang.getString("allowMultiBoost") + ": " + allowIt +"\n";
|
|
}
|
|
str+=boostUpgrade.getDesc(translatedValue);
|
|
|
|
if(targetType==abtAlly)
|
|
{
|
|
str+= lang.getString("AffectedUnitsFromTeam") +":\n";
|
|
}
|
|
else if(targetType==abtFoe)
|
|
{
|
|
str+= lang.getString("AffectedUnitsFromFoe") +":\n";
|
|
}
|
|
else if(targetType==abtFaction)
|
|
{
|
|
str+= lang.getString("AffectedUnitsFromYourFaction") +":\n";
|
|
}
|
|
else if(targetType==abtUnitTypes)
|
|
{
|
|
str+= lang.getString("AffectedUnitsFromAll") +":\n";
|
|
}
|
|
else if(targetType==abtAll)
|
|
{
|
|
str+= lang.getString("AffectedUnitsFromAll") +":\n";
|
|
}
|
|
|
|
if(boostUnitList.empty() && tags.empty()) {
|
|
str+= lang.getString("All")+"\n";
|
|
}
|
|
else
|
|
{
|
|
// We want the output to be sorted, so convert the set to a vector and sort that
|
|
std::vector<const UnitType*> outputUnits(boostUnitList.begin(), boostUnitList.end());
|
|
std::sort(outputUnits.begin(), outputUnits.end(), UnitTypeSorter());
|
|
|
|
vector<const UnitType*>::iterator unitIter;
|
|
for (unitIter = outputUnits.begin(); unitIter != outputUnits.end(); ++unitIter) {
|
|
const UnitType *unit = *unitIter;
|
|
str+= indent+unit->getName(translatedValue)+"\n";
|
|
}
|
|
|
|
// Do the same for tags
|
|
std::vector<string> outputTags(tags.begin(), tags.end());
|
|
std::sort(outputTags.begin(), outputTags.end());
|
|
|
|
vector<string>::iterator tagIter;
|
|
for (tagIter = outputTags.begin(); tagIter != outputTags.end(); ++tagIter) {
|
|
string tag = *tagIter;
|
|
str+= indent + lang.getString("TagDesc", (translatedValue == true ? "" : "english")) +
|
|
" " + getTagName(tag,translatedValue) + "\n";
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
else
|
|
return "";
|
|
}
|
|
|
|
void AttackBoost::loadGame(const XmlNode *rootNode, Faction *faction, const SkillType *skillType) {
|
|
const XmlNode *attackBoostNode = rootNode->getChild("AttackBoost");
|
|
|
|
enabled = (attackBoostNode->getAttribute("enabled")->getIntValue() != 0);
|
|
allowMultipleBoosts = (attackBoostNode->getAttribute("allowMultipleBoosts")->getIntValue() != 0);
|
|
radius = attackBoostNode->getAttribute("radius")->getIntValue();
|
|
targetType = static_cast<AttackBoostTargetType>(attackBoostNode->getAttribute("targetType")->getIntValue());
|
|
|
|
if(attackBoostNode->hasChild("UnitType") == true) {
|
|
vector<XmlNode *> attackBoostNodeList = attackBoostNode->getChildList("UnitType");
|
|
for(unsigned int i = 0; i < attackBoostNodeList.size(); ++i) {
|
|
XmlNode *node = attackBoostNodeList[i];
|
|
|
|
string unitTypeName = node->getAttribute("name")->getValue();
|
|
const UnitType *unitType = faction->getType()->getUnitType(unitTypeName);
|
|
if(unitType != NULL) {
|
|
boostUnitList.insert(unitType);
|
|
}
|
|
}
|
|
}
|
|
if(attackBoostNode->hasChild("tag")) {
|
|
vector<XmlNode *> tagNodeList = attackBoostNode->getChildList("tag");
|
|
for(unsigned int i = 0; i < tagNodeList.size(); ++i) {
|
|
XmlNode *node = tagNodeList[i];
|
|
string tagName = node->getAttribute("name")->getValue();
|
|
tags.insert(tagName);
|
|
}
|
|
}
|
|
//boostUpgrade.loadGame(attackBoostNode,faction);
|
|
boostUpgrade = skillType->getAttackBoost()->boostUpgrade;
|
|
|
|
unitParticleSystemTypeForSourceUnit = new UnitParticleSystemType();
|
|
unitParticleSystemTypeForSourceUnit->loadGame(attackBoostNode);
|
|
|
|
unitParticleSystemTypeForAffectedUnit = new UnitParticleSystemType();
|
|
unitParticleSystemTypeForAffectedUnit->loadGame(attackBoostNode);
|
|
|
|
includeSelf = (attackBoostNode->getAttribute("includeSelf")->getIntValue() != 0);
|
|
name = attackBoostNode->getAttribute("name")->getValue();
|
|
}
|
|
|
|
void AttackBoost::saveGame(XmlNode *rootNode) const {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *attackBoostNode = rootNode->addChild("AttackBoost");
|
|
|
|
// bool enabled;
|
|
attackBoostNode->addAttribute("enabled",intToStr(enabled), mapTagReplacements);
|
|
// bool allowMultipleBoosts;
|
|
attackBoostNode->addAttribute("allowMultipleBoosts",intToStr(allowMultipleBoosts), mapTagReplacements);
|
|
// int radius;
|
|
attackBoostNode->addAttribute("radius",intToStr(radius), mapTagReplacements);
|
|
// AttackBoostTargetType targetType;
|
|
attackBoostNode->addAttribute("targetType",intToStr(targetType), mapTagReplacements);
|
|
// vector<const UnitType *> boostUnitList;
|
|
std::set<const UnitType*>::iterator unitIter;
|
|
for (unitIter = boostUnitList.begin(); unitIter != boostUnitList.end(); ++unitIter) {
|
|
const UnitType *unit = *unitIter;
|
|
XmlNode *unitTypeNode = attackBoostNode->addChild("UnitType");
|
|
unitTypeNode->addAttribute("name",unit->getName(false), mapTagReplacements);
|
|
}
|
|
std::set<string>::iterator tagIter;
|
|
for (tagIter = tags.begin(); tagIter != tags.end(); ++tagIter) {
|
|
string tag = *tagIter;
|
|
XmlNode *unitTypeNode = attackBoostNode->addChild("tag");
|
|
unitTypeNode->addAttribute("name", tag, mapTagReplacements);
|
|
}
|
|
// UpgradeTypeBase boostUpgrade;
|
|
boostUpgrade.saveGame(attackBoostNode);
|
|
// UnitParticleSystemType *unitParticleSystemTypeForSourceUnit;
|
|
if(unitParticleSystemTypeForSourceUnit != NULL) {
|
|
unitParticleSystemTypeForSourceUnit->saveGame(attackBoostNode);
|
|
}
|
|
// UnitParticleSystemType *unitParticleSystemTypeForAffectedUnit;
|
|
if(unitParticleSystemTypeForAffectedUnit != NULL) {
|
|
unitParticleSystemTypeForAffectedUnit->saveGame(attackBoostNode);
|
|
}
|
|
|
|
// bool includeSelf;
|
|
attackBoostNode->addAttribute("includeSelf",intToStr(includeSelf), mapTagReplacements);
|
|
// string name;
|
|
attackBoostNode->addAttribute("name",name, mapTagReplacements);
|
|
}
|
|
|
|
// =====================================================
|
|
// class SkillSound
|
|
// =====================================================
|
|
SkillSound::SkillSound(){
|
|
startTime=0.0f;
|
|
}
|
|
SkillSound::~SkillSound()
|
|
{
|
|
deleteValues(soundContainer.getSounds().begin(), soundContainer.getSounds().end());
|
|
startTime=0.0f;
|
|
//soundContainer
|
|
}
|
|
// =====================================================
|
|
// class SkillType
|
|
// =====================================================
|
|
|
|
SkillType::~SkillType() {
|
|
while(!skillSoundList.empty()) {
|
|
delete skillSoundList.back();
|
|
skillSoundList.pop_back();
|
|
}
|
|
//remove unitParticleSystemTypes
|
|
while(!unitParticleSystemTypes.empty()) {
|
|
delete unitParticleSystemTypes.back();
|
|
unitParticleSystemTypes.pop_back();
|
|
}
|
|
}
|
|
|
|
const XmlNode * SkillType::findAttackBoostDetails(string attackBoostName,
|
|
const XmlNode *attackBoostsNode,const XmlNode *attackBoostNode) {
|
|
const XmlNode *result = attackBoostNode;
|
|
|
|
if(attackBoostsNode != NULL && attackBoostName != "") {
|
|
for(int i = 0; i < (int)attackBoostsNode->getChildCount(); ++i) {
|
|
const XmlNode *abn= attackBoostsNode->getChild("attack-boost", i);
|
|
|
|
string sharedName = abn->getAttribute("name")->getRestrictedValue();
|
|
if(sharedName == attackBoostName) {
|
|
result = abn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void SkillType::loadAttackBoost(const XmlNode *attackBoostsNode, const XmlNode *attackBoostNode,
|
|
const FactionType *ft, string parentLoader, const string & dir,
|
|
string currentPath, std::map<string,vector<pair<string,string> > > & loadedFileList,
|
|
const TechTree *tt) {
|
|
|
|
attackBoost.enabled = true;
|
|
if(attackBoostNode->hasAttribute("name") == true) {
|
|
attackBoost.name = attackBoostNode->getAttribute("name")->getRestrictedValue();
|
|
|
|
attackBoostNode = findAttackBoostDetails(attackBoost.name,attackBoostsNode,attackBoostNode);
|
|
}
|
|
else {
|
|
attackBoost.name = "attack-boost-autoname-" + intToStr(getNextAttackBoostId());
|
|
}
|
|
string targetType = attackBoostNode->getChild("target")->getAttribute("value")->getValue();
|
|
|
|
attackBoost.allowMultipleBoosts = false;
|
|
if(attackBoostNode->hasChild("allow-multiple-boosts") == true) {
|
|
attackBoost.allowMultipleBoosts = attackBoostNode->getChild("allow-multiple-boosts")->getAttribute("value")->getBoolValue();
|
|
}
|
|
|
|
attackBoost.radius = attackBoostNode->getChild("radius")->getAttribute("value")->getIntValue();
|
|
|
|
attackBoost.includeSelf = false;
|
|
if(attackBoostNode->getChild("target")->hasAttribute("include-self") == true) {
|
|
attackBoost.includeSelf = attackBoostNode->getChild("target")->getAttribute("include-self")->getBoolValue();
|
|
}
|
|
|
|
if(targetType == "ally") {
|
|
attackBoost.targetType = abtAlly;
|
|
}
|
|
else if(targetType == "foe") {
|
|
attackBoost.targetType = abtFoe;
|
|
}
|
|
else if(targetType == "faction") {
|
|
attackBoost.targetType = abtFaction;
|
|
}
|
|
else if(targetType == "unit-types") {
|
|
attackBoost.targetType = abtUnitTypes;
|
|
}
|
|
else if(targetType == "all") {
|
|
attackBoost.targetType = abtAll;
|
|
}
|
|
else {
|
|
char szBuf[8096] = "";
|
|
snprintf(szBuf, 8096,"Unsupported target [%s] specified for attack boost for skill [%s] in [%s]", targetType.c_str(), name.c_str(), parentLoader.c_str());
|
|
throw megaglest_runtime_error(szBuf);
|
|
}
|
|
|
|
// Load the regular targets
|
|
const XmlNode *targetNode = attackBoostNode->getChild("target");
|
|
vector<XmlNode*> targetNodes = targetNode->getChildList("unit-type");
|
|
for(size_t i = 0;i < targetNodes.size(); ++i) {
|
|
string unitName = targetNodes.at(i)->getAttribute("name")->getRestrictedValue();
|
|
attackBoost.boostUnitList.insert(ft->getUnitType(unitName));
|
|
}
|
|
|
|
// Load tags
|
|
vector<XmlNode*> tagNodes = targetNode->getChildList("tag");
|
|
for(size_t i = 0;i < tagNodes.size(); ++i) {
|
|
string unitName = tagNodes.at(i)->getAttribute("name")->getRestrictedValue();
|
|
attackBoost.tags.insert(unitName);
|
|
}
|
|
|
|
attackBoost.boostUpgrade.load(attackBoostNode,attackBoost.name);
|
|
if(attackBoostNode->hasChild("particles") == true) {
|
|
const XmlNode *particleNode = attackBoostNode->getChild("particles");
|
|
bool particleEnabled = particleNode->getAttribute("value")->getBoolValue();
|
|
if(particleEnabled == true) {
|
|
if(particleNode->hasChild("originator-particle-file") == true){
|
|
const XmlNode *particleFileNode = particleNode->getChild("originator-particle-file");
|
|
string path = particleFileNode->getAttribute("path")->getRestrictedValue();
|
|
attackBoost.unitParticleSystemTypeForSourceUnit = new UnitParticleSystemType();
|
|
attackBoost.unitParticleSystemTypeForSourceUnit->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(), loadedFileList, parentLoader, tt->getPath());
|
|
loadedFileList[currentPath + path].push_back(make_pair(parentLoader, particleFileNode->getAttribute("path")->getRestrictedValue()));
|
|
}
|
|
if(particleNode->hasChild("affected-particle-file") == true) {
|
|
const XmlNode *particleFileNode = particleNode->getChild("affected-particle-file");
|
|
string path = particleFileNode->getAttribute("path")->getRestrictedValue();
|
|
attackBoost.unitParticleSystemTypeForAffectedUnit = new UnitParticleSystemType();
|
|
attackBoost.unitParticleSystemTypeForAffectedUnit->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(), loadedFileList, parentLoader, tt->getPath());
|
|
loadedFileList[currentPath + path].push_back(make_pair(parentLoader, particleFileNode->getAttribute("path")->getRestrictedValue()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt, const FactionType *ft,
|
|
std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
//name
|
|
name= sn->getChild("name")->getAttribute("value")->getRestrictedValue();
|
|
|
|
//ep cost
|
|
if(sn->hasChild("ep-cost") == true) {
|
|
mpCost = sn->getChild("ep-cost")->getAttribute("value")->getIntValue();
|
|
}
|
|
else {
|
|
mpCost = 0;
|
|
}
|
|
|
|
if (sn->hasChild("hp-cost") == true) {
|
|
hpCost = sn->getChild("hp-cost")->getAttribute("value")->getIntValue();
|
|
}
|
|
else {
|
|
hpCost = 0;
|
|
}
|
|
|
|
//speed
|
|
if(sn->hasChild("speed") == true) {
|
|
speed = sn->getChild("speed")->getAttribute("value")->getIntValue();
|
|
}
|
|
else {
|
|
speed = 0;
|
|
}
|
|
|
|
//anim speed
|
|
if(sn->hasChild("anim-speed") == true) {
|
|
animSpeed = sn->getChild("anim-speed")->getAttribute("value")->getIntValue();
|
|
}
|
|
else {
|
|
animSpeed = 0;
|
|
}
|
|
|
|
//model
|
|
string currentPath = dir;
|
|
endPathWithSlash(currentPath);
|
|
|
|
animationRandomCycleMaxcount = -1;
|
|
if(sn->hasChild("animation-random-cycle-maxcount") == true) {
|
|
const XmlNode *randomCycleCountNode = sn->getChild("animation-random-cycle-maxcount");
|
|
animationRandomCycleMaxcount = randomCycleCountNode->getAttribute("value")->getIntValue();
|
|
}
|
|
|
|
if(sn->hasChild("animation") == true) {
|
|
//string path= sn->getChild("animation")->getAttribute("path")->getRestrictedValue(currentPath);
|
|
vector<XmlNode *> animationList = sn->getChildList("animation");
|
|
for(unsigned int i = 0; i < animationList.size(); ++i) {
|
|
string path= animationList[i]->getAttribute("path")->getRestrictedValue(currentPath);
|
|
if(fileExists(path) == true) {
|
|
Model *animation= Renderer::getInstance().newModel(rsGame, path, false, &loadedFileList, &parentLoader);
|
|
loadedFileList[path].push_back(make_pair(parentLoader,animationList[i]->getAttribute("path")->getRestrictedValue()));
|
|
|
|
animations.push_back(animation);
|
|
//printf("**FOUND ANIMATION [%s]\n",path.c_str());
|
|
|
|
AnimationAttributes animationAttributeList;
|
|
if(animationList[i]->getAttribute("minHp",false) != NULL && animationList[i]->getAttribute("maxHp",false) != NULL) {
|
|
animationAttributeList.fromHp = animationList[i]->getAttribute("minHp")->getIntValue();
|
|
animationAttributeList.toHp = animationList[i]->getAttribute("maxHp")->getIntValue();
|
|
}
|
|
animationAttributes.push_back(animationAttributeList);
|
|
}
|
|
else {
|
|
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line %d] WARNING CANNOT LOAD MODEL [%s] for parentLoader [%s]\n",__FILE__,__FUNCTION__,__LINE__,path.c_str(),parentLoader.c_str());
|
|
}
|
|
}
|
|
if(animations.empty() == true) {
|
|
char szBuf[8096]="";
|
|
snprintf(szBuf,8096,"Error no animations found for skill [%s] for parentLoader [%s]",name.c_str(),parentLoader.c_str());
|
|
throw megaglest_runtime_error(szBuf);
|
|
}
|
|
}
|
|
|
|
//particles
|
|
if(sn->hasChild("particles")) {
|
|
const XmlNode *particleNode= sn->getChild("particles");
|
|
bool particleEnabled= particleNode->getAttribute("value")->getBoolValue();
|
|
if(particleEnabled) {
|
|
for(int i = 0; i < (int)particleNode->getChildCount(); ++i) {
|
|
const XmlNode *particleFileNode= particleNode->getChild("particle-file", i);
|
|
string path= particleFileNode->getAttribute("path")->getRestrictedValue();
|
|
UnitParticleSystemType *unitParticleSystemType= new UnitParticleSystemType();
|
|
unitParticleSystemType->load(particleFileNode, dir, currentPath + path, &Renderer::getInstance(),
|
|
loadedFileList,parentLoader,tt->getPath());
|
|
|
|
if (particleNode->getChild(i)->hasAttribute("start-time")) {
|
|
//printf("*NOTE particle system type has start-time [%f]\n",particleNode->getAttribute("start-time")->getFloatValue());
|
|
unitParticleSystemType->setStartTime(particleNode->getChild(i)->getAttribute("start-time")->getFloatValue());
|
|
} else if (particleNode->hasAttribute("start-time")) {
|
|
//printf("*NOTE particle system type has start-time [%f]\n",particleNode->getAttribute("start-time")->getFloatValue());
|
|
unitParticleSystemType->setStartTime(particleNode->getAttribute("start-time")->getFloatValue());
|
|
}
|
|
|
|
if (particleNode->getChild(i)->hasAttribute("end-time")) {
|
|
//printf("*NOTE particle system type has start-time [%f]\n",particleNode->getAttribute("start-time")->getFloatValue());
|
|
unitParticleSystemType->setEndTime(particleNode->getChild(i)->getAttribute("end-time")->getFloatValue());
|
|
} else if (particleNode->hasAttribute("end-time")) {
|
|
//printf("*NOTE particle system type has end-time [%f]\n",particleNode->getAttribute("end-time")->getFloatValue());
|
|
unitParticleSystemType->setEndTime(particleNode->getAttribute("end-time")->getFloatValue());
|
|
}
|
|
|
|
loadedFileList[currentPath + path].push_back(make_pair(parentLoader,particleFileNode->getAttribute("path")->getRestrictedValue()));
|
|
unitParticleSystemTypes.push_back(unitParticleSystemType);
|
|
}
|
|
}
|
|
}
|
|
|
|
//sound
|
|
vector<XmlNode *> soundNodeList = sn->getChildList("sound");
|
|
for(unsigned int i = 0; i < soundNodeList.size(); ++i) {
|
|
const XmlNode *soundNode= soundNodeList[i];
|
|
if(soundNode->getAttribute("enabled")->getBoolValue()) {
|
|
float soundStartTime= soundNode->getAttribute("start-time")->getFloatValue();
|
|
SkillSound *skillSound = new SkillSound();
|
|
skillSound->setStartTime(soundStartTime);
|
|
|
|
skillSound->getSoundContainer()->resize((int)soundNode->getChildCount());
|
|
skillSoundList.push_back(skillSound);
|
|
for(int i = 0; i < (int)soundNode->getChildCount(); ++i) {
|
|
const XmlNode *soundFileNode= soundNode->getChild("sound-file", i);
|
|
string path= soundFileNode->getAttribute("path")->getRestrictedValue(currentPath, true);
|
|
|
|
StaticSound *sound= new StaticSound();
|
|
sound->load(path);
|
|
loadedFileList[path].push_back(make_pair(parentLoader,soundFileNode->getAttribute("path")->getRestrictedValue()));
|
|
(*skillSound->getSoundContainer())[i]= sound;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// attack-boost
|
|
if(sn->hasChild("attack-boost") == true) {
|
|
//printf("$$FOUND ATTACK BOOST FOR [%s]\n",parentLoader.c_str());
|
|
const XmlNode *attackBoostNode = sn->getChild("attack-boost");
|
|
loadAttackBoost(attackBoostsNode, attackBoostNode, ft, parentLoader, dir, currentPath, loadedFileList, tt);
|
|
}
|
|
|
|
shake=false;
|
|
shakeIntensity=50;
|
|
shakeDuration=300;
|
|
shakeStartTime=0.0f;
|
|
shakeSelfEnabled=false;
|
|
shakeSelfVisible=true;
|
|
shakeSelfInCameraView=false;
|
|
shakeSelfCameraAffected=false;
|
|
shakeTeamEnabled=false;
|
|
shakeTeamVisible=true;
|
|
shakeTeamInCameraView=false;
|
|
shakeTeamCameraAffected=false;
|
|
shakeEnemyEnabled=false;
|
|
shakeEnemyVisible=true;
|
|
shakeEnemyInCameraView=false;
|
|
shakeEnemyCameraAffected=false;
|
|
|
|
if (sn->hasChild("shake")) {
|
|
XmlNode *shakeNode=sn->getChild("shake");
|
|
shake= shakeNode->getAttribute("enabled")->getBoolValue();
|
|
shakeIntensity= shakeNode->getAttribute("intensity")->getIntValue();
|
|
shakeDuration= shakeNode->getAttribute("duration")->getIntValue();
|
|
if (shakeNode->hasAttribute("start-time")) {
|
|
shakeStartTime= shakeNode->getAttribute("start-time")->getFloatValue();
|
|
}
|
|
if (shakeNode->hasChild("self")) {
|
|
shakeSelfEnabled= shakeNode->getChild("enemy")->getAttribute("enabled")->getBoolValue();
|
|
shakeSelfVisible= shakeNode->getChild("self")->getAttribute("visible")->getBoolValue();
|
|
shakeSelfInCameraView= shakeNode->getChild("self")->getAttribute("in-camera-view")->getBoolValue();
|
|
shakeSelfCameraAffected= shakeNode->getChild("self")->getAttribute("camera-distance-affected")->getBoolValue();
|
|
}
|
|
if (shakeNode->hasChild("team")) {
|
|
shakeTeamEnabled= shakeNode->getChild("enemy")->getAttribute("enabled")->getBoolValue();
|
|
shakeTeamVisible= shakeNode->getChild("team")->getAttribute("visible")->getBoolValue();
|
|
shakeTeamInCameraView= shakeNode->getChild("team")->getAttribute("in-camera-view")->getBoolValue();
|
|
shakeTeamCameraAffected= shakeNode->getChild("team")->getAttribute("camera-distance-affected")->getBoolValue();
|
|
}
|
|
if (shakeNode->hasChild("enemy")) {
|
|
shakeEnemyEnabled= shakeNode->getChild("enemy")->getAttribute("enabled")->getBoolValue();
|
|
shakeEnemyVisible= shakeNode->getChild("enemy")->getAttribute("visible")->getBoolValue();
|
|
shakeEnemyInCameraView= shakeNode->getChild("enemy")->getAttribute("in-camera-view")->getBoolValue();
|
|
shakeEnemyCameraAffected= shakeNode->getChild("enemy")->getAttribute("camera-distance-affected")->getBoolValue();
|
|
}
|
|
|
|
//visible-for (team, self,all, team-and-visible, self-and-visible, all-and-visible )
|
|
|
|
}
|
|
}
|
|
|
|
bool SkillType::CanCycleNextRandomAnimation(const int *animationRandomCycleCount) const {
|
|
bool result = true;
|
|
if(animations.size() > 1) {
|
|
if( animationRandomCycleMaxcount >= 0 &&
|
|
animationRandomCycleCount != NULL &&
|
|
*animationRandomCycleCount >= animationRandomCycleMaxcount) {
|
|
result = false;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const AnimationAttributes SkillType::getAnimationAttribute(int index) const {
|
|
return animationAttributes[index];
|
|
}
|
|
|
|
Model *SkillType::getAnimation(float animProgress, const Unit *unit,
|
|
int *lastAnimationIndex, int *animationRandomCycleCount) const {
|
|
int modelIndex = 0;
|
|
//printf("Count [%d] animProgress = [%f] for skill [%s] animationRandomCycleCount = %d\n",animations.size(),animProgress,name.c_str(),*animationRandomCycleCount);
|
|
if(animations.size() > 1) {
|
|
//printf("animProgress = [%f] for skill [%s] animationRandomCycleCount = %d\n",animProgress,name.c_str(),*animationRandomCycleCount);
|
|
|
|
if(lastAnimationIndex) {
|
|
modelIndex = *lastAnimationIndex;
|
|
}
|
|
if(modelIndex < 0 || animProgress > 1.0f) {
|
|
bool canCycle = CanCycleNextRandomAnimation(animationRandomCycleCount);
|
|
if(canCycle == true) {
|
|
vector<int> filteredAnimations;
|
|
bool foundSpecificAnimation = false;
|
|
if(unit != NULL) {
|
|
for(unsigned int i = 0; i < animationAttributes.size(); ++i) {
|
|
const AnimationAttributes &attributes = animationAttributes[i];
|
|
if(attributes.fromHp != 0 || attributes.toHp != 0) {
|
|
if(unit->getHp() >= attributes.fromHp && unit->getHp() <= attributes.toHp) {
|
|
modelIndex = i;
|
|
foundSpecificAnimation = true;
|
|
filteredAnimations.push_back(i);
|
|
//printf("SELECTING Model index = %d [%s] model attributes [%d to %d] for unit [%s - %d] with HP = %d\n",i,animations[modelIndex]->getFileName().c_str(),attributes.fromHp,attributes.toHp,unit->getType()->getName().c_str(),unit->getId(),unit->getHp());
|
|
//break;
|
|
}
|
|
}
|
|
}
|
|
// Need to make sure the filtered list does NOT include any
|
|
// models with min/max hp
|
|
if(foundSpecificAnimation == false) {
|
|
for(unsigned int i = 0; i < animationAttributes.size(); ++i) {
|
|
const AnimationAttributes &attributes = animationAttributes[i];
|
|
if(attributes.fromHp == 0 && attributes.toHp == 0) {
|
|
modelIndex = i;
|
|
foundSpecificAnimation = true;
|
|
filteredAnimations.push_back(i);
|
|
//printf("SELECTING Model index = %d [%s] model attributes [%d to %d] for unit [%s - %d] with HP = %d\n",i,animations[modelIndex]->getFileName().c_str(),attributes.fromHp,attributes.toHp,unit->getType()->getName().c_str(),unit->getId(),unit->getHp());
|
|
//break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(foundSpecificAnimation == false) {
|
|
//int modelIndex = random.randRange(0,animations.size()-1);
|
|
Chrono seed(true);
|
|
srand((unsigned int)seed.getCurTicks() + (unit != NULL ? unit->getId() : 0));
|
|
|
|
modelIndex = rand() % animations.size();
|
|
|
|
//const AnimationAttributes &attributes = animationAttributes[modelIndex];
|
|
//printf("SELECTING RANDOM Model index = %d [%s] model attributes [%d to %d] for unit [%s - %d] with HP = %d\n",modelIndex,animations[modelIndex]->getFileName().c_str(),attributes.fromHp,attributes.toHp,unit->getType()->getName().c_str(),unit->getId(),unit->getHp());
|
|
}
|
|
else {
|
|
Chrono seed(true);
|
|
srand((unsigned int)seed.getCurTicks() + unit->getId());
|
|
|
|
int filteredModelIndex = rand() % filteredAnimations.size();
|
|
modelIndex = filteredAnimations[filteredModelIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(lastAnimationIndex) {
|
|
if(*lastAnimationIndex != modelIndex) {
|
|
//printf("Switching model from [%s] to [%s]\n",(*lastAnimationIndex >= 0 ? animations[*lastAnimationIndex]->getFileName().c_str() : "none"),animations[modelIndex]->getFileName().c_str());
|
|
}
|
|
*lastAnimationIndex = modelIndex;
|
|
}
|
|
|
|
//printf("!!RETURN ANIMATION [%d / %d]\n",modelIndex,animations.size()-1);
|
|
return animations[modelIndex];
|
|
}
|
|
|
|
string SkillType::skillClassToStr(SkillClass skillClass) {
|
|
switch(skillClass){
|
|
case scStop: return "Stop";
|
|
case scMove: return "Move";
|
|
case scAttack: return "Attack";
|
|
case scHarvest: return "Harvest";
|
|
case scRepair: return "Repair";
|
|
case scBuild: return "Build";
|
|
case scDie: return "Die";
|
|
case scBeBuilt: return "Be Built";
|
|
case scProduce: return "Produce";
|
|
case scUpgrade: return "Upgrade";
|
|
case scFogOfWar: return "Fog Of War";
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
string SkillType::fieldToStr(Field field) {
|
|
Lang &lang= Lang::getInstance();
|
|
string fieldName = "";
|
|
switch(field) {
|
|
case fLand:
|
|
if(lang.hasString("FieldLand") == true) {
|
|
fieldName = lang.getString("FieldLand");
|
|
}
|
|
else {
|
|
fieldName = "Land";
|
|
}
|
|
//return "Land";
|
|
return lang.getTilesetString("FieldLandName",fieldName.c_str());
|
|
|
|
case fAir:
|
|
if(lang.hasString("FieldAir") == true) {
|
|
fieldName = lang.getString("FieldAir");
|
|
}
|
|
else {
|
|
fieldName = "Air";
|
|
}
|
|
|
|
//return "Air";
|
|
return lang.getTilesetString("FieldAirName",fieldName.c_str());
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void SkillType::saveGame(XmlNode *rootNode) {
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *skillTypeNode = rootNode->addChild("SkillType");
|
|
|
|
// SkillClass skillClass;
|
|
skillTypeNode->addAttribute("skillClass",intToStr(skillClass), mapTagReplacements);
|
|
// string name;
|
|
skillTypeNode->addAttribute("name",name, mapTagReplacements);
|
|
// int mpCost;
|
|
skillTypeNode->addAttribute("mpCost",intToStr(mpCost), mapTagReplacements);
|
|
// int hpCost;
|
|
skillTypeNode->addAttribute("hpCost",intToStr(hpCost), mapTagReplacements);
|
|
// int speed;
|
|
skillTypeNode->addAttribute("speed",intToStr(speed), mapTagReplacements);
|
|
// int animSpeed;
|
|
skillTypeNode->addAttribute("animSpeed",intToStr(animSpeed), mapTagReplacements);
|
|
// int animationRandomCycleMaxcount;
|
|
skillTypeNode->addAttribute("animationRandomCycleMaxcount",intToStr(animationRandomCycleMaxcount), mapTagReplacements);
|
|
// vector<Model *> animations;
|
|
// vector<AnimationAttributes> animationAttributes;
|
|
//
|
|
// SoundContainer sounds;
|
|
// float soundStartTime;
|
|
// skillTypeNode->addAttribute("soundStartTime",floatToStr(soundStartTime,6), mapTagReplacements);
|
|
// RandomGen random;
|
|
skillTypeNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements);
|
|
// AttackBoost attackBoost;
|
|
attackBoost.saveGame(skillTypeNode);
|
|
// static int nextAttackBoostId;
|
|
skillTypeNode->addAttribute("nextAttackBoostId",intToStr(nextAttackBoostId), mapTagReplacements);
|
|
// UnitParticleSystemTypes unitParticleSystemTypes;
|
|
for(UnitParticleSystemTypes::iterator it = unitParticleSystemTypes.begin(); it != unitParticleSystemTypes.end(); ++it) {
|
|
(*it)->saveGame(skillTypeNode);
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// class StopSkillType
|
|
// =====================================================
|
|
|
|
StopSkillType::StopSkillType(){
|
|
skillClass= scStop;
|
|
}
|
|
|
|
string StopSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Stop";
|
|
}
|
|
return Lang::getInstance().getString("Stop");
|
|
}
|
|
|
|
// =====================================================
|
|
// class MoveSkillType
|
|
// =====================================================
|
|
|
|
MoveSkillType::MoveSkillType(){
|
|
skillClass= scMove;
|
|
}
|
|
|
|
string MoveSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Move";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Move");
|
|
}
|
|
|
|
int MoveSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{
|
|
int result = speed + totalUpgrade->getMoveSpeed(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
// =====================================================
|
|
// class AttackSkillType
|
|
// =====================================================
|
|
|
|
//varios
|
|
AttackSkillType::AttackSkillType() {
|
|
skillClass= scAttack;
|
|
attackType= NULL;
|
|
projectile= false;
|
|
splash= false;
|
|
splashRadius= 0;
|
|
spawnUnit="";
|
|
spawnUnitcount=0;
|
|
spawnUnitAtTarget=false;
|
|
splashParticleSystemType= NULL;
|
|
|
|
for(int i = 0; i < fieldCount; ++i) {
|
|
attackFields[i]= false;
|
|
}
|
|
|
|
attackStrength=0;
|
|
attackVar=0;
|
|
attackRange=0;
|
|
attackStartTime=0;
|
|
splashDamageAll=false;
|
|
}
|
|
|
|
AttackSkillType::~AttackSkillType() {
|
|
|
|
deleteValues(projectileTypes.begin(), projectileTypes.end());
|
|
|
|
delete splashParticleSystemType;
|
|
splashParticleSystemType = NULL;
|
|
deleteValues(projSounds.getSounds().begin(), projSounds.getSounds().end());
|
|
projSounds.clearSounds();
|
|
}
|
|
|
|
void AttackSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
string currentPath = dir;
|
|
endPathWithSlash(currentPath);
|
|
|
|
//misc
|
|
std::vector<string> attackStrengthXMLTags;
|
|
attackStrengthXMLTags.push_back("attack-strenght");
|
|
attackStrengthXMLTags.push_back("attack-strength");
|
|
attackStrength= sn->getChildWithAliases(attackStrengthXMLTags)->getAttribute("value")->getIntValue();
|
|
attackVar= sn->getChild("attack-var")->getAttribute("value")->getIntValue();
|
|
|
|
if(attackVar < 0) {
|
|
char szBuf[8096]="";
|
|
snprintf(szBuf,8096,"The attack skill has an INVALID attack var value which is < 0 [%d] in file [%s]!",attackVar,dir.c_str());
|
|
throw megaglest_runtime_error(szBuf);
|
|
}
|
|
|
|
attackRange= sn->getChild("attack-range")->getAttribute("value")->getIntValue();
|
|
string attackTypeName= sn->getChild("attack-type")->getAttribute("value")->getRestrictedValue();
|
|
attackType= tt->getAttackType(attackTypeName);
|
|
attackStartTime= sn->getChild("attack-start-time")->getAttribute("value")->getFloatValue();
|
|
|
|
if (sn->hasChild("unit")) {
|
|
spawnUnit = sn->getChild("unit")->getAttribute("value")->getValue();
|
|
spawnUnitcount = sn->getChild("unit")->getAttribute("amount")->getIntValue();
|
|
if(sn->getChild("unit")->hasAttribute("spawnAtTarget")) {
|
|
spawnUnitAtTarget = sn->getChild("unit")->getAttribute("spawnAtTarget")->getBoolValue();
|
|
} else {
|
|
spawnUnitAtTarget = false;
|
|
}
|
|
} else {
|
|
spawnUnit = "";
|
|
spawnUnitcount = 0;
|
|
spawnUnitAtTarget = false;
|
|
}
|
|
//attack fields
|
|
const XmlNode *attackFieldsNode= sn->getChild("attack-fields");
|
|
for(int i=0; i < (int)attackFieldsNode->getChildCount(); ++i){
|
|
const XmlNode *fieldNode= attackFieldsNode->getChild("field", i);
|
|
string fieldName= fieldNode->getAttribute("value")->getRestrictedValue();
|
|
if(fieldName=="land"){
|
|
attackFields[fLand]= true;
|
|
}
|
|
else if(fieldName=="air"){
|
|
attackFields[fAir]= true;
|
|
}
|
|
else{
|
|
throw megaglest_runtime_error("Not a valid field: "+fieldName+": "+ dir);
|
|
}
|
|
}
|
|
|
|
if(sn->hasChild("projectile")){
|
|
//projectile -- backward compatible old behaviour with only one projectile
|
|
const XmlNode *projectileNode= sn->getChild("projectile");
|
|
projectile= projectileNode->getAttribute("value")->getBoolValue();
|
|
if(projectile){
|
|
// create new projectile
|
|
ProjectileType *projectileType=new ProjectileType();
|
|
projectileTypes.push_back(projectileType);
|
|
projectileType->setAttackStartTime(attackStartTime);
|
|
projectileType->setDamagePercentage(100);
|
|
//proj particle
|
|
if(projectileNode->hasChild("particle")){
|
|
const XmlNode *particleNode= projectileNode->getChild("particle");
|
|
bool particleEnabled= particleNode->getAttribute("value")->getBoolValue();
|
|
if(particleEnabled){
|
|
string path= particleNode->getAttribute("path")->getRestrictedValue();
|
|
ParticleSystemTypeProjectile* projectileParticleSystemType= new ParticleSystemTypeProjectile();
|
|
projectileParticleSystemType->load(particleNode, dir, currentPath + path,
|
|
&Renderer::getInstance(), loadedFileList, parentLoader,
|
|
tt->getPath());
|
|
loadedFileList[currentPath + path].push_back(make_pair(parentLoader,particleNode->getAttribute("path")->getRestrictedValue()));
|
|
projectileType->setProjectileParticleSystemType(projectileParticleSystemType);
|
|
}
|
|
}
|
|
//proj sounds
|
|
const XmlNode *soundNode= projectileNode->getChild("sound");
|
|
if(soundNode->getAttribute("enabled")->getBoolValue()){
|
|
|
|
projSounds.resize((int)soundNode->getChildCount());
|
|
for(int i=0; i < (int)soundNode->getChildCount(); ++i){
|
|
const XmlNode *soundFileNode= soundNode->getChild("sound-file", i);
|
|
string path= soundFileNode->getAttribute("path")->getRestrictedValue(currentPath, true);
|
|
//printf("\n\n\n\n!@#$ ---> parentLoader [%s] path [%s] nodeValue [%s] i = %d",parentLoader.c_str(),path.c_str(),soundFileNode->getAttribute("path")->getRestrictedValue().c_str(),i);
|
|
|
|
StaticSound *sound= new StaticSound();
|
|
sound->load(path);
|
|
loadedFileList[path].push_back(make_pair(parentLoader,soundFileNode->getAttribute("path")->getRestrictedValue()));
|
|
projSounds[i]= sound;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
const XmlNode *projectilesNode= sn->getChild("projectiles");
|
|
vector<XmlNode *> projectilesNodeList = projectilesNode->getChildList("projectile");
|
|
int totalDamagePercentage=0;
|
|
for(unsigned int i = 0; i < projectilesNodeList.size(); ++i) {
|
|
const XmlNode *projectileNode= projectilesNodeList[i];
|
|
ProjectileType *projectileType=new ProjectileType();
|
|
projectileType->load(projectileNode,dir, tt->getPath(), loadedFileList, parentLoader);
|
|
totalDamagePercentage += projectileType->getDamagePercentage();
|
|
projectileTypes.push_back(projectileType);
|
|
projectile=true;
|
|
}
|
|
|
|
if(totalDamagePercentage!=100){
|
|
throw megaglest_runtime_error("Damages percentages of projectiles don't sum up to 100 %");
|
|
}
|
|
|
|
if(sn->hasChild("hitsound")==true){
|
|
//general hit sounds, individual ones can be set in projectiles
|
|
const XmlNode *soundNode= sn->getChild("hitsound");
|
|
if(soundNode->getAttribute("enabled")->getBoolValue()){
|
|
|
|
projSounds.resize((int)soundNode->getChildCount());
|
|
for(int i=0; i < (int)soundNode->getChildCount(); ++i){
|
|
const XmlNode *soundFileNode= soundNode->getChild("sound-file", i);
|
|
string path= soundFileNode->getAttribute("path")->getRestrictedValue(currentPath, true);
|
|
//printf("\n\n\n\n!@#$ ---> parentLoader [%s] path [%s] nodeValue [%s] i = %d",parentLoader.c_str(),path.c_str(),soundFileNode->getAttribute("path")->getRestrictedValue().c_str(),i);
|
|
|
|
StaticSound *sound= new StaticSound();
|
|
sound->load(path);
|
|
loadedFileList[path].push_back(make_pair(parentLoader,soundFileNode->getAttribute("path")->getRestrictedValue()));
|
|
projSounds[i]= sound;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//splash
|
|
const XmlNode *splashNode= sn->getChild("splash");
|
|
splash= splashNode->getAttribute("value")->getBoolValue();
|
|
if(splash){
|
|
splashRadius= splashNode->getChild("radius")->getAttribute("value")->getIntValue();
|
|
splashDamageAll= splashNode->getChild("damage-all")->getAttribute("value")->getBoolValue();
|
|
|
|
//splash particle
|
|
const XmlNode *particleNode= splashNode->getChild("particle");
|
|
bool particleEnabled= particleNode->getAttribute("value")->getBoolValue();
|
|
if(particleEnabled){
|
|
string path= particleNode->getAttribute("path")->getRestrictedValue();
|
|
splashParticleSystemType= new ParticleSystemTypeSplash();
|
|
splashParticleSystemType->load(particleNode, dir, currentPath + path,
|
|
&Renderer::getInstance(),loadedFileList, parentLoader,
|
|
tt->getPath());
|
|
}
|
|
}
|
|
}
|
|
|
|
int AttackSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{
|
|
int result = speed + totalUpgrade->getAttackSpeed(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
// Get the amount to boost the attack animation speed by (based on attack-speed upgrades)
|
|
int AttackSkillType::getAnimSpeedBoost(const TotalUpgrade *totalUpgrade) const{
|
|
// Same calculation as in TotalUpgrade::sum, but bypassing the use of the value
|
|
// list (which is for the attack speed, not animation speed)
|
|
if(totalUpgrade->getAttackRangeIsMultiplier()) {
|
|
return animSpeed * (totalUpgrade->getAttackSpeed(NULL) / (double)100);
|
|
}
|
|
else {
|
|
return totalUpgrade->getAttackSpeed(NULL);
|
|
}
|
|
}
|
|
|
|
string AttackSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Attack";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Attack");
|
|
}
|
|
|
|
//get totals
|
|
int AttackSkillType::getTotalAttackStrength(const TotalUpgrade *totalUpgrade) const{
|
|
int result = attackStrength + totalUpgrade->getAttackStrength(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
int AttackSkillType::getTotalAttackRange(const TotalUpgrade *totalUpgrade) const{
|
|
int result = attackRange + totalUpgrade->getAttackRange(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
void AttackSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *attackSkillTypeNode = rootNode->addChild("AttackSkillType");
|
|
|
|
// int attackStrength;
|
|
attackSkillTypeNode->addAttribute("attackStrength",intToStr(attackStrength), mapTagReplacements);
|
|
// int attackVar;
|
|
attackSkillTypeNode->addAttribute("attackVar",intToStr(attackVar), mapTagReplacements);
|
|
// int attackRange;
|
|
attackSkillTypeNode->addAttribute("attackRange",intToStr(attackRange), mapTagReplacements);
|
|
// const AttackType *attackType;
|
|
if(attackType != NULL) {
|
|
attackSkillTypeNode->addAttribute("attackType",attackType->getName(false), mapTagReplacements);
|
|
}
|
|
// bool attackFields[fieldCount];
|
|
for(unsigned int i = 0; i < fieldCount; ++i) {
|
|
XmlNode *attackFieldsNode = attackSkillTypeNode->addChild("attackFields");
|
|
attackFieldsNode->addAttribute("key",intToStr(i), mapTagReplacements);
|
|
attackFieldsNode->addAttribute("value",intToStr(attackFields[i]), mapTagReplacements);
|
|
}
|
|
// float attackStartTime;
|
|
attackSkillTypeNode->addAttribute("attackStartTime",floatToStr(attackStartTime,6), mapTagReplacements);
|
|
// string spawnUnit;
|
|
attackSkillTypeNode->addAttribute("spawnUnit",spawnUnit, mapTagReplacements);
|
|
// int spawnUnitcount;
|
|
attackSkillTypeNode->addAttribute("spawnUnitcount",intToStr(spawnUnitcount), mapTagReplacements);
|
|
// bool spawnUnitAtTarget;
|
|
attackSkillTypeNode->addAttribute("spawnUnitAtTarget",intToStr(spawnUnitAtTarget), mapTagReplacements);
|
|
// bool projectile;
|
|
attackSkillTypeNode->addAttribute("projectile",intToStr(projectile), mapTagReplacements);
|
|
// ParticleSystemTypeProjectile* projectileParticleSystemType;
|
|
// save a skill_type ????
|
|
// if(projectileParticleSystemType != NULL) {
|
|
// projectileParticleSystemType->saveGame(attackSkillTypeNode);
|
|
// }
|
|
// SoundContainer projSounds;
|
|
//
|
|
// bool splash;
|
|
attackSkillTypeNode->addAttribute("splash",intToStr(splash), mapTagReplacements);
|
|
// int splashRadius;
|
|
attackSkillTypeNode->addAttribute("splashRadius",intToStr(splashRadius), mapTagReplacements);
|
|
// bool splashDamageAll;
|
|
attackSkillTypeNode->addAttribute("splashDamageAll",intToStr(splashDamageAll), mapTagReplacements);
|
|
// ParticleSystemTypeSplash* splashParticleSystemType;
|
|
if(splashParticleSystemType != NULL) {
|
|
splashParticleSystemType->saveGame(attackSkillTypeNode);
|
|
}
|
|
}
|
|
// =====================================================
|
|
// class BuildSkillType
|
|
// =====================================================
|
|
|
|
BuildSkillType::BuildSkillType(){
|
|
skillClass= scBuild;
|
|
}
|
|
|
|
string BuildSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Build";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Build");
|
|
}
|
|
|
|
// =====================================================
|
|
// class HarvestSkillType
|
|
// =====================================================
|
|
|
|
HarvestSkillType::HarvestSkillType(){
|
|
skillClass= scHarvest;
|
|
}
|
|
|
|
string HarvestSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Harvest";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Harvest");
|
|
}
|
|
|
|
// =====================================================
|
|
// class RepairSkillType
|
|
// =====================================================
|
|
|
|
RepairSkillType::RepairSkillType(){
|
|
skillClass= scRepair;
|
|
}
|
|
|
|
string RepairSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Repair";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Repair");
|
|
}
|
|
|
|
// =====================================================
|
|
// class ProduceSkillType
|
|
// =====================================================
|
|
|
|
ProduceSkillType::ProduceSkillType(){
|
|
skillClass= scProduce;
|
|
animProgressBound=false;
|
|
}
|
|
|
|
void ProduceSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
if(sn->hasChild("anim-progress-bound")){
|
|
animProgressBound= sn->getChild("anim-progress-bound")->getAttribute("value")->getBoolValue();
|
|
}
|
|
else {
|
|
animProgressBound=false;
|
|
}
|
|
}
|
|
|
|
|
|
string ProduceSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Produce";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Produce");
|
|
}
|
|
|
|
int ProduceSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{
|
|
int result = speed + totalUpgrade->getProdSpeed(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
void ProduceSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *produceSkillTypeNode = rootNode->addChild("ProduceSkillType");
|
|
|
|
produceSkillTypeNode->addAttribute("animProgressBound",intToStr(animProgressBound), mapTagReplacements);
|
|
}
|
|
// =====================================================
|
|
// class UpgradeSkillType
|
|
// =====================================================
|
|
|
|
UpgradeSkillType::UpgradeSkillType(){
|
|
skillClass= scUpgrade;
|
|
animProgressBound=false;
|
|
}
|
|
|
|
void UpgradeSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
if(sn->hasChild("anim-progress-bound")){
|
|
animProgressBound= sn->getChild("anim-progress-bound")->getAttribute("value")->getBoolValue();
|
|
}
|
|
else {
|
|
animProgressBound=false;
|
|
}
|
|
}
|
|
|
|
string UpgradeSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Upgrade";
|
|
}
|
|
|
|
return Lang::getInstance().getString("Upgrade");
|
|
}
|
|
|
|
int UpgradeSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{
|
|
int result = speed + totalUpgrade->getProdSpeed(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
void UpgradeSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *upgradeSkillTypeNode = rootNode->addChild("UpgradeSkillType");
|
|
|
|
upgradeSkillTypeNode->addAttribute("animProgressBound",intToStr(animProgressBound), mapTagReplacements);
|
|
}
|
|
|
|
// =====================================================
|
|
// class BeBuiltSkillType
|
|
// =====================================================
|
|
|
|
BeBuiltSkillType::BeBuiltSkillType(){
|
|
skillClass= scBeBuilt;
|
|
animProgressBound=false;
|
|
}
|
|
|
|
void BeBuiltSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
if(sn->hasChild("anim-progress-bound")){
|
|
animProgressBound= sn->getChild("anim-progress-bound")->getAttribute("value")->getBoolValue();
|
|
}
|
|
else if(sn->hasChild("anim-hp-bound")){ // deprecated!!!! remove it when you see it after 15th July 2011
|
|
animProgressBound= sn->getChild("anim-hp-bound")->getAttribute("value")->getBoolValue();
|
|
}
|
|
else {
|
|
animProgressBound=false;
|
|
}
|
|
}
|
|
|
|
|
|
string BeBuiltSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Be built";
|
|
}
|
|
|
|
return "Be built";
|
|
}
|
|
|
|
void BeBuiltSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *beBuiltSkillTypeNode = rootNode->addChild("BeBuiltSkillType");
|
|
|
|
beBuiltSkillTypeNode->addAttribute("animProgressBound",intToStr(animProgressBound), mapTagReplacements);
|
|
}
|
|
|
|
// =====================================================
|
|
// class MorphSkillType
|
|
// =====================================================
|
|
|
|
MorphSkillType::MorphSkillType(){
|
|
skillClass= scMorph;
|
|
animProgressBound=false;
|
|
}
|
|
|
|
void MorphSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
if(sn->hasChild("anim-progress-bound")){
|
|
animProgressBound= sn->getChild("anim-progress-bound")->getAttribute("value")->getBoolValue();
|
|
}
|
|
else {
|
|
animProgressBound=false;
|
|
}
|
|
}
|
|
|
|
string MorphSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Morph";
|
|
}
|
|
|
|
return "Morph";
|
|
}
|
|
|
|
int MorphSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{
|
|
int result = speed + totalUpgrade->getProdSpeed(this);
|
|
result = max(0,result);
|
|
return result;
|
|
}
|
|
|
|
void MorphSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *morphSkillTypeNode = rootNode->addChild("MorphSkillType");
|
|
|
|
morphSkillTypeNode->addAttribute("animProgressBound",intToStr(animProgressBound), mapTagReplacements);
|
|
}
|
|
|
|
// =====================================================
|
|
// class DieSkillType
|
|
// =====================================================
|
|
|
|
DieSkillType::DieSkillType(){
|
|
skillClass= scDie;
|
|
fade=false;
|
|
}
|
|
|
|
void DieSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
fade= sn->getChild("fade")->getAttribute("value")->getBoolValue();
|
|
}
|
|
|
|
string DieSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "Die";
|
|
}
|
|
|
|
return "Die";
|
|
}
|
|
|
|
void DieSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *dieSkillTypeNode = rootNode->addChild("DieSkillType");
|
|
|
|
dieSkillTypeNode->addAttribute("fade",intToStr(fade), mapTagReplacements);
|
|
}
|
|
|
|
StaticSound *DieSkillType::getSound() const{
|
|
if(skillSoundList.size()==0){
|
|
return NULL;
|
|
}
|
|
else {
|
|
return skillSoundList.front()->getSoundContainer()->getRandSound();
|
|
}
|
|
}
|
|
|
|
|
|
// =====================================================
|
|
// class FogOfWarSkillType
|
|
// =====================================================
|
|
|
|
FogOfWarSkillType::FogOfWarSkillType(){
|
|
skillClass= scFogOfWar;
|
|
|
|
fowEnable = false;
|
|
applyToTeam = false;
|
|
durationTime = 0;
|
|
}
|
|
|
|
void FogOfWarSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
|
const string &dir, const TechTree *tt,
|
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
|
string parentLoader) {
|
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
|
|
|
fowEnable = sn->getChild("enable-fog")->getAttribute("value")->getBoolValue();
|
|
applyToTeam = sn->getChild("apply-team")->getAttribute("value")->getBoolValue();
|
|
durationTime = sn->getChild("duration")->getAttribute("value")->getFloatValue();
|
|
}
|
|
|
|
string FogOfWarSkillType::toString(bool translatedValue) const{
|
|
if(translatedValue == false) {
|
|
return "FogOfWar";
|
|
}
|
|
|
|
return "FogOfWar";
|
|
}
|
|
|
|
void FogOfWarSkillType::saveGame(XmlNode *rootNode) {
|
|
SkillType::saveGame(rootNode);
|
|
std::map<string,string> mapTagReplacements;
|
|
XmlNode *fogSkillTypeNode = rootNode->addChild("FogOfWarSkillType");
|
|
|
|
fogSkillTypeNode->addAttribute("enable-fog",intToStr(fowEnable), mapTagReplacements);
|
|
fogSkillTypeNode->addAttribute("apply-team",intToStr(applyToTeam), mapTagReplacements);
|
|
fogSkillTypeNode->addAttribute("duration",floatToStr(durationTime,6), mapTagReplacements);
|
|
}
|
|
|
|
// =====================================================
|
|
// class SkillTypeFactory
|
|
// =====================================================
|
|
|
|
SkillTypeFactory::SkillTypeFactory(){
|
|
registerClass<StopSkillType>("stop");
|
|
registerClass<MoveSkillType>("move");
|
|
registerClass<AttackSkillType>("attack");
|
|
registerClass<BuildSkillType>("build");
|
|
registerClass<BeBuiltSkillType>("be_built");
|
|
registerClass<HarvestSkillType>("harvest");
|
|
registerClass<RepairSkillType>("repair");
|
|
registerClass<ProduceSkillType>("produce");
|
|
registerClass<UpgradeSkillType>("upgrade");
|
|
registerClass<MorphSkillType>("morph");
|
|
registerClass<DieSkillType>("die");
|
|
registerClass<FogOfWarSkillType>("fog_of_war");
|
|
}
|
|
|
|
SkillTypeFactory &SkillTypeFactory::getInstance(){
|
|
static SkillTypeFactory ctf;
|
|
return ctf;
|
|
}
|
|
|
|
}} //end namespace
|