spawn units on death

as requested here https://forum.megaglest.org/index.php?topic=9879.0
This commit is contained in:
titiger 2016-11-20 16:19:53 +01:00
parent 661b512a8a
commit 374634b630
4 changed files with 143 additions and 42 deletions

View File

@ -1354,6 +1354,13 @@ void MorphSkillType::saveGame(XmlNode *rootNode) {
DieSkillType::DieSkillType(){
skillClass= scDie;
fade=false;
spawn=false;
spawnStartTime=0;
spawnUnit="";
spawnUnitcount=0;
spawnUnitHealthPercentMin=100;
spawnUnitHealthPercentMax=100;
spawnProbability=100;
}
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);
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{
@ -1379,6 +1398,7 @@ void DieSkillType::saveGame(XmlNode *rootNode) {
XmlNode *dieSkillTypeNode = rootNode->addChild("DieSkillType");
dieSkillTypeNode->addAttribute("fade",intToStr(fade), mapTagReplacements);
// no need to save spawn attributes
}
StaticSound *DieSkillType::getSound() const{

View File

@ -476,16 +476,31 @@ public:
class DieSkillType: public SkillType {
private:
bool fade;
bool spawn;
float spawnStartTime;
string spawnUnit;
int spawnUnitcount;
int spawnUnitHealthPercentMin;
int spawnUnitHealthPercentMax;
int spawnProbability;
public:
DieSkillType();
bool getFade() const {return fade;}
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,
string parentLoader);
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);
StaticSound *getSound() const;
};

View File

@ -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());
//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
if(unit->getCurrSkill()->getClass() == scAttack) {
const AttackSkillType *ast= static_cast<const AttackSkillType*>(unit->getCurrSkill());
@ -275,7 +296,10 @@ bool UnitUpdater::updateUnit(Unit *unit) {
if (act != NULL && act->getAttackSkillType() != NULL
&& act->getAttackSkillType()->getSpawnUnit() != ""
&& 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;
}
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) {
const FactionType *ft= unit->getFaction()->getType();
const UnitType *spawnUnitType = ft->getUnitType(spawnUnit);
int spawnCount = spawnUnitcount;
for (int y=0; y < spawnCount; ++y) {
if(spawnUnitType->getMaxUnitCount() > 0) {
if(spawnUnitType->getMaxUnitCount() <= unit->getFaction()->getCountForMaxUnitCount(spawnUnitType)) {
break;
if (probability > 0 && probability < 100
&& unit->getRandom()->randRange(1, 100) <= probability) {
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;
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
newpath = new UnitPathBasic();
break;
default:
throw megaglest_runtime_error("detected unsupported pathfinder type!");
}
// no stat count !!
//world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
}
}
}
Unit *spawned= new Unit(world->getNextUnitId(unit->getFaction()), newpath,
Vec2i(0), spawnUnitType, unit->getFaction(),
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());
void UnitUpdater::spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability,bool spawnUnitAtTarget,Vec2i targetPos) {
if(spawnUnit != "" && spawnUnitcount > 0) {
// This will also cleanup newPath
delete spawned;
spawned = NULL;
int spawnCount = spawnUnitcount;
for (int y=0; y < spawnCount; ++y) {
if (probability > 0 && probability < 100
&& unit->getRandom()->randRange(1, 100) <= probability) {
continue;
}
else {
spawned->create();
spawned->born(NULL);
world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
Unit* spawned=this->spawnUnit(unit,spawnUnit,spawnUnitAtTarget?targetPos:unit->getCenteredPos());
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);
}
// no stat count !!
// world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
const CommandType *ct= spawned->getType()->getFirstAttackCommand(unit->getTargetField());
if(ct == NULL){
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__);
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 ====================
//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
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

View File

@ -103,7 +103,6 @@ public:
//update skills
bool updateUnit(Unit *unit);
void spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,bool spawnUnitAtTarget,Vec2i targetPos=Vec2i(-10,-10));
//update commands
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);
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);
void SwapActiveCommand(Unit *unitSrc, Unit *unitDest);
void SwapActiveCommandState(Unit *unit, CommandStateType commandStateType,