spawn units on death
as requested here https://forum.megaglest.org/index.php?topic=9879.0
This commit is contained in:
parent
661b512a8a
commit
374634b630
|
@ -1354,6 +1354,13 @@ void MorphSkillType::saveGame(XmlNode *rootNode) {
|
||||||
DieSkillType::DieSkillType(){
|
DieSkillType::DieSkillType(){
|
||||||
skillClass= scDie;
|
skillClass= scDie;
|
||||||
fade=false;
|
fade=false;
|
||||||
|
spawn=false;
|
||||||
|
spawnStartTime=0;
|
||||||
|
spawnUnit="";
|
||||||
|
spawnUnitcount=0;
|
||||||
|
spawnUnitHealthPercentMin=100;
|
||||||
|
spawnUnitHealthPercentMax=100;
|
||||||
|
spawnProbability=100;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DieSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
void DieSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
||||||
|
@ -1363,6 +1370,18 @@ void DieSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode,
|
||||||
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
SkillType::load(sn, attackBoostsNode,dir, tt, ft, loadedFileList, parentLoader);
|
||||||
|
|
||||||
fade= sn->getChild("fade")->getAttribute("value")->getBoolValue();
|
fade= sn->getChild("fade")->getAttribute("value")->getBoolValue();
|
||||||
|
if(sn->hasChild("spawn")){
|
||||||
|
const XmlNode *spawnNode= sn->getChild("spawn");
|
||||||
|
spawn=true;
|
||||||
|
spawnStartTime=spawnNode->getAttribute("start-time")->getFloatValue();
|
||||||
|
spawnUnit = spawnNode->getChild("unit")->getAttribute("value")->getValue();
|
||||||
|
spawnUnitcount = spawnNode->hasChild("amount")?spawnNode->getChild("amount")->getAttribute("value")->getIntValue():0;
|
||||||
|
if(spawnNode->hasChild("health-percent")){
|
||||||
|
spawnUnitHealthPercentMin = spawnNode->getChild("health-percent")->getAttribute("min")->getIntValue();
|
||||||
|
spawnUnitHealthPercentMax = spawnNode->getChild("health-percent")->getAttribute("max")->getIntValue();
|
||||||
|
}
|
||||||
|
spawnProbability = spawnNode->hasChild("probability")?spawnNode->getChild("probability")->getAttribute("value")->getIntValue():spawnProbability;
|
||||||
|
} // else keep defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
string DieSkillType::toString(bool translatedValue) const{
|
string DieSkillType::toString(bool translatedValue) const{
|
||||||
|
@ -1379,6 +1398,7 @@ void DieSkillType::saveGame(XmlNode *rootNode) {
|
||||||
XmlNode *dieSkillTypeNode = rootNode->addChild("DieSkillType");
|
XmlNode *dieSkillTypeNode = rootNode->addChild("DieSkillType");
|
||||||
|
|
||||||
dieSkillTypeNode->addAttribute("fade",intToStr(fade), mapTagReplacements);
|
dieSkillTypeNode->addAttribute("fade",intToStr(fade), mapTagReplacements);
|
||||||
|
// no need to save spawn attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticSound *DieSkillType::getSound() const{
|
StaticSound *DieSkillType::getSound() const{
|
||||||
|
|
|
@ -476,16 +476,31 @@ public:
|
||||||
class DieSkillType: public SkillType {
|
class DieSkillType: public SkillType {
|
||||||
private:
|
private:
|
||||||
bool fade;
|
bool fade;
|
||||||
|
bool spawn;
|
||||||
|
float spawnStartTime;
|
||||||
|
string spawnUnit;
|
||||||
|
int spawnUnitcount;
|
||||||
|
int spawnUnitHealthPercentMin;
|
||||||
|
int spawnUnitHealthPercentMax;
|
||||||
|
int spawnProbability;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DieSkillType();
|
DieSkillType();
|
||||||
bool getFade() const {return fade;}
|
|
||||||
|
|
||||||
virtual void load(const XmlNode *sn, const XmlNode *attackBoostsNode, const string &dir, const TechTree *tt,
|
virtual void load(const XmlNode *sn, const XmlNode *attackBoostsNode, const string &dir, const TechTree *tt,
|
||||||
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
const FactionType *ft, std::map<string,vector<pair<string, string> > > &loadedFileList,
|
||||||
string parentLoader);
|
string parentLoader);
|
||||||
virtual string toString(bool translatedValue) const;
|
virtual string toString(bool translatedValue) const;
|
||||||
|
|
||||||
|
bool getFade() const {return fade;}
|
||||||
|
bool getSpawn() const {return spawn;}
|
||||||
|
inline int getSpawnStartTime() const {return spawnStartTime;}
|
||||||
|
inline string getSpawnUnit() const {return spawnUnit;}
|
||||||
|
inline int getSpawnUnitCount() const {return spawnUnitcount;}
|
||||||
|
inline int getSpawnUnitHealthPercentMin() const {return spawnUnitHealthPercentMin;}
|
||||||
|
inline int getSpawnUnitHealthPercentMax() const {return spawnUnitHealthPercentMax;}
|
||||||
|
inline int getSpawnProbability() const {return spawnProbability;}
|
||||||
|
|
||||||
virtual void saveGame(XmlNode *rootNode);
|
virtual void saveGame(XmlNode *rootNode);
|
||||||
StaticSound *getSound() const;
|
StaticSound *getSound() const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -182,6 +182,27 @@ bool UnitUpdater::updateUnit(Unit *unit) {
|
||||||
|
|
||||||
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after playsound]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
|
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after playsound]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
|
||||||
|
|
||||||
|
|
||||||
|
//start attack particle system
|
||||||
|
if(unit->getCurrSkill()->getClass() == scDie) {
|
||||||
|
const DieSkillType *dst= static_cast<const DieSkillType*>(unit->getCurrSkill());
|
||||||
|
|
||||||
|
if(dst->getSpawn() == true){
|
||||||
|
float spawnStartTime = truncateDecimal<float>(dst->getSpawnStartTime(),6);
|
||||||
|
float lastAnimProgress = truncateDecimal<float>(unit->getLastAnimProgressAsFloat(),6);
|
||||||
|
float animProgress = truncateDecimal<float>(unit->getAnimProgressAsFloat(),6);
|
||||||
|
|
||||||
|
bool startSpawnNow = (spawnStartTime >= lastAnimProgress && spawnStartTime < animProgress);
|
||||||
|
if(startSpawnNow){
|
||||||
|
// spawn the units
|
||||||
|
spawn(unit, dst->getSpawnUnit(), dst->getSpawnUnitCount(),
|
||||||
|
dst->getSpawnUnitHealthPercentMin(),
|
||||||
|
dst->getSpawnUnitHealthPercentMax(),
|
||||||
|
dst->getSpawnProbability());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//start attack particle system
|
//start attack particle system
|
||||||
if(unit->getCurrSkill()->getClass() == scAttack) {
|
if(unit->getCurrSkill()->getClass() == scAttack) {
|
||||||
const AttackSkillType *ast= static_cast<const AttackSkillType*>(unit->getCurrSkill());
|
const AttackSkillType *ast= static_cast<const AttackSkillType*>(unit->getCurrSkill());
|
||||||
|
@ -275,7 +296,10 @@ bool UnitUpdater::updateUnit(Unit *unit) {
|
||||||
if (act != NULL && act->getAttackSkillType() != NULL
|
if (act != NULL && act->getAttackSkillType() != NULL
|
||||||
&& act->getAttackSkillType()->getSpawnUnit() != ""
|
&& act->getAttackSkillType()->getSpawnUnit() != ""
|
||||||
&& act->getAttackSkillType()->getSpawnUnitCount() > 0) {
|
&& act->getAttackSkillType()->getSpawnUnitCount() > 0) {
|
||||||
spawnAttack(unit,act->getAttackSkillType()->getSpawnUnit(),act->getAttackSkillType()->getSpawnUnitCount(),act->getAttackSkillType()->getSpawnUnitAtTarget());
|
spawnAttack(unit, act->getAttackSkillType()->getSpawnUnit(),
|
||||||
|
act->getAttackSkillType()->getSpawnUnitCount(), 100,
|
||||||
|
100, 100,
|
||||||
|
act->getAttackSkillType()->getSpawnUnitAtTarget());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,51 +337,46 @@ bool UnitUpdater::updateUnit(Unit *unit) {
|
||||||
return processUnitCommand;
|
return processUnitCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnitUpdater::spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,bool spawnUnitAtTarget,Vec2i targetPos) {
|
void UnitUpdater::spawn(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability) {
|
||||||
if(spawnUnit != "" && spawnUnitcount > 0) {
|
if(spawnUnit != "" && spawnUnitcount > 0) {
|
||||||
|
|
||||||
const FactionType *ft= unit->getFaction()->getType();
|
|
||||||
const UnitType *spawnUnitType = ft->getUnitType(spawnUnit);
|
|
||||||
int spawnCount = spawnUnitcount;
|
int spawnCount = spawnUnitcount;
|
||||||
for (int y=0; y < spawnCount; ++y) {
|
for (int y=0; y < spawnCount; ++y) {
|
||||||
if(spawnUnitType->getMaxUnitCount() > 0) {
|
if (probability > 0 && probability < 100
|
||||||
if(spawnUnitType->getMaxUnitCount() <= unit->getFaction()->getCountForMaxUnitCount(spawnUnitType)) {
|
&& unit->getRandom()->randRange(1, 100) <= probability) {
|
||||||
break;
|
continue;
|
||||||
|
}
|
||||||
|
Unit* spawned=this->spawnUnit(unit,spawnUnit);
|
||||||
|
if(spawned!=NULL){
|
||||||
|
if(healthMin>0 && healthMin<100 && healthMax>=healthMin && healthMax<=100){
|
||||||
|
int damagePercent=100-unit->getRandom()->randRange(healthMin, healthMax);
|
||||||
|
//printf("damagePercent=%d\n",damagePercent);
|
||||||
|
spawned->decHp((spawned->getHp()*damagePercent)/100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UnitPathInterface *newpath = NULL;
|
// no stat count !!
|
||||||
switch(this->game->getGameSettings()->getPathFinderType()) {
|
//world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
|
||||||
case pfBasic:
|
}
|
||||||
newpath = new UnitPathBasic();
|
}
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
throw megaglest_runtime_error("detected unsupported pathfinder type!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Unit *spawned= new Unit(world->getNextUnitId(unit->getFaction()), newpath,
|
void UnitUpdater::spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability,bool spawnUnitAtTarget,Vec2i targetPos) {
|
||||||
Vec2i(0), spawnUnitType, unit->getFaction(),
|
if(spawnUnit != "" && spawnUnitcount > 0) {
|
||||||
world->getMap(), CardinalDir::NORTH);
|
|
||||||
//SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to place unit for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,spawned->toString().c_str());
|
|
||||||
bool placedSpawnUnit=false;
|
|
||||||
if(targetPos==Vec2i(-10,-10)) {
|
|
||||||
targetPos=unit->getTargetPos();
|
|
||||||
}
|
|
||||||
if(spawnUnitAtTarget) {
|
|
||||||
placedSpawnUnit=world->placeUnit(targetPos, 10, spawned);
|
|
||||||
} else {
|
|
||||||
placedSpawnUnit=world->placeUnit(unit->getCenteredPos(), 10, spawned);
|
|
||||||
}
|
|
||||||
if(!placedSpawnUnit) {
|
|
||||||
//SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] COULD NOT PLACE UNIT for unitID [%d]\n",__FILE__,__FUNCTION__,__LINE__,spawned->getId());
|
|
||||||
|
|
||||||
// This will also cleanup newPath
|
int spawnCount = spawnUnitcount;
|
||||||
delete spawned;
|
for (int y=0; y < spawnCount; ++y) {
|
||||||
spawned = NULL;
|
if (probability > 0 && probability < 100
|
||||||
|
&& unit->getRandom()->randRange(1, 100) <= probability) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
Unit* spawned=this->spawnUnit(unit,spawnUnit,spawnUnitAtTarget?targetPos:unit->getCenteredPos());
|
||||||
spawned->create();
|
if(spawned!=NULL){
|
||||||
spawned->born(NULL);
|
if(healthMin>0 && healthMin<100 && healthMax>=healthMin && healthMax<=100){
|
||||||
world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
|
int damagePercent=100-unit->getRandom()->randRange(healthMin, healthMax);
|
||||||
|
//printf("damagePercent=%d\n",damagePercent);
|
||||||
|
spawned->decHp((spawned->getHp()*damagePercent)/100);
|
||||||
|
}
|
||||||
|
// no stat count !!
|
||||||
|
// world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
|
||||||
const CommandType *ct= spawned->getType()->getFirstAttackCommand(unit->getTargetField());
|
const CommandType *ct= spawned->getType()->getFirstAttackCommand(unit->getTargetField());
|
||||||
if(ct == NULL){
|
if(ct == NULL){
|
||||||
ct= spawned->computeCommandType(targetPos,map->getCell(targetPos)->getUnit(unit->getTargetField()));
|
ct= spawned->computeCommandType(targetPos,map->getCell(targetPos)->getUnit(unit->getTargetField()));
|
||||||
|
@ -366,12 +385,54 @@ void UnitUpdater::spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,boo
|
||||||
if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
spawned->giveCommand(new Command(ct, targetPos));
|
spawned->giveCommand(new Command(ct, targetPos));
|
||||||
}
|
}
|
||||||
scriptManager->onUnitCreated(spawned);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Unit* UnitUpdater::spawnUnit(Unit *unit,string spawnUnit,Vec2i spawnPos) {
|
||||||
|
const FactionType *ft= unit->getFaction()->getType();
|
||||||
|
const UnitType *spawnUnitType = ft->getUnitType(spawnUnit);
|
||||||
|
Vec2i _spawnPos=spawnPos;
|
||||||
|
if(_spawnPos==Vec2i(-10,-10)) {
|
||||||
|
_spawnPos=unit->getCenteredPos();
|
||||||
|
}
|
||||||
|
if(spawnUnitType->getMaxUnitCount() > 0) {
|
||||||
|
if(spawnUnitType->getMaxUnitCount() <= unit->getFaction()->getCountForMaxUnitCount(spawnUnitType)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitPathInterface *newpath = NULL;
|
||||||
|
switch(this->game->getGameSettings()->getPathFinderType()) {
|
||||||
|
case pfBasic:
|
||||||
|
newpath = new UnitPathBasic();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw megaglest_runtime_error("detected unsupported pathfinder type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit *spawned= new Unit(world->getNextUnitId(unit->getFaction()), newpath,
|
||||||
|
Vec2i(0), spawnUnitType, unit->getFaction(),
|
||||||
|
world->getMap(), CardinalDir::NORTH);
|
||||||
|
|
||||||
|
bool placedSpawnUnit=world->placeUnit(_spawnPos, 10, spawned);
|
||||||
|
|
||||||
|
if(!placedSpawnUnit) {
|
||||||
|
// This will also cleanup newPath
|
||||||
|
delete spawned;
|
||||||
|
spawned = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spawned->create();
|
||||||
|
spawned->born(NULL);
|
||||||
|
scriptManager->onUnitCreated(spawned);
|
||||||
|
}
|
||||||
|
return spawned;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ==================== progress commands ====================
|
// ==================== progress commands ====================
|
||||||
|
|
||||||
//VERY IMPORTANT: compute next state depending on the first order of the list
|
//VERY IMPORTANT: compute next state depending on the first order of the list
|
||||||
|
@ -3339,7 +3400,9 @@ void ParticleDamager::update(ParticleSystem *particleSystem) {
|
||||||
|
|
||||||
//check for spawnattack
|
//check for spawnattack
|
||||||
if(projectileType->getSpawnUnit()!="" && projectileType->getSpawnUnitcount()>0 ){
|
if(projectileType->getSpawnUnit()!="" && projectileType->getSpawnUnitcount()>0 ){
|
||||||
unitUpdater->spawnAttack(attacker,projectileType->getSpawnUnit(),projectileType->getSpawnUnitcount(),projectileType->getSpawnUnitAtTarget(),targetPos);
|
unitUpdater->spawnAttack(attacker, projectileType->getSpawnUnit(), 100,
|
||||||
|
100, 100, projectileType->getSpawnUnitcount(),
|
||||||
|
projectileType->getSpawnUnitAtTarget(), targetPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for shake and shake
|
// check for shake and shake
|
||||||
|
|
|
@ -103,7 +103,6 @@ public:
|
||||||
|
|
||||||
//update skills
|
//update skills
|
||||||
bool updateUnit(Unit *unit);
|
bool updateUnit(Unit *unit);
|
||||||
void spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,bool spawnUnitAtTarget,Vec2i targetPos=Vec2i(-10,-10));
|
|
||||||
|
|
||||||
//update commands
|
//update commands
|
||||||
void updateUnitCommand(Unit *unit, int frameIndex);
|
void updateUnitCommand(Unit *unit, int frameIndex);
|
||||||
|
@ -153,6 +152,10 @@ private:
|
||||||
bool unitOnRange(Unit *unit, int range, Unit **enemyPtr, const AttackSkillType *ast,bool evalMode=false);
|
bool unitOnRange(Unit *unit, int range, Unit **enemyPtr, const AttackSkillType *ast,bool evalMode=false);
|
||||||
void enemiesAtDistance(const Unit *unit, const Unit *priorityUnit, int distance, vector<Unit*> &enemies);
|
void enemiesAtDistance(const Unit *unit, const Unit *priorityUnit, int distance, vector<Unit*> &enemies);
|
||||||
|
|
||||||
|
void spawn(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability);
|
||||||
|
void spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability,bool spawnUnitAtTarget,Vec2i targetPos=Vec2i(-10,-10));
|
||||||
|
Unit* spawnUnit(Unit *unit,string spawnUnit,Vec2i targetPos=Vec2i(-10,-10));
|
||||||
|
|
||||||
Unit * findPeerUnitBuilder(Unit *unit);
|
Unit * findPeerUnitBuilder(Unit *unit);
|
||||||
void SwapActiveCommand(Unit *unitSrc, Unit *unitDest);
|
void SwapActiveCommand(Unit *unitSrc, Unit *unitDest);
|
||||||
void SwapActiveCommandState(Unit *unit, CommandStateType commandStateType,
|
void SwapActiveCommandState(Unit *unit, CommandStateType commandStateType,
|
||||||
|
|
Loading…
Reference in New Issue