/** ******************************************************************************* @file /gui/engine/SceneScripts.cpp @brief Formace jednotky, razeni vojacku v utvarech, boj, stavba @author Vajicek @version 0.1 ******************************************************************************/ #include #include #include "gui/engine/SceneScripts.h" #include "gui/model/guiUnit.h" #include "gui/model/guiBuilding.h" #include "gui/model/guimap.h" #include "gui/common/mymath_ext.h" #include "gui/common/init_env.h" #include "common/Log.h" using namespace std; //----------------------------------------------------------------------------- namespace gui{ #ifdef _DEBUG static TLog scriptlogger(1); #endif #define SCLOG //scriptlogger.LogMsg void dumpvi(std::vector* ic){ for(std::vector::iterator it = (*ic).begin(); it != (*ic).end(); it++) printf("%d, ",*it); printf("\n"); } //TSceneScript //----------------------------------------------------------------------------- vector TSceneScript::vSceneScriptInstances; TSceneScript::~TSceneScript(){ if(guimap){ SCLOG("executing sceneScriptFinished_sensor\n"); guimap->sceneScriptFinished_sensor(); } for(std::vector::iterator it = TSceneScript::vSceneScriptInstances.begin(); it != TSceneScript::vSceneScriptInstances.end(); it++) { if((*it) == this ){ TSceneScript::vSceneScriptInstances.erase(it); break; } }//for } TSceneScript::TSceneScript(TguiMap* scene){ guimap = scene; TSceneScript::vSceneScriptInstances.push_back(this); } void TSceneScript::report(){ char buffer[255]; SCLOG( "Reporting active scripts: %d active scripts:\n" "--------------------------------------------\n", (int)TSceneScript::vSceneScriptInstances.size()); for(vector::iterator it = TSceneScript::vSceneScriptInstances.begin(); it != TSceneScript::vSceneScriptInstances.end(); it++) { (*it)->getStatusMsg(buffer,255); SCLOG(buffer); SCLOG("\n"); } } //TCombat //----------------------------------------------------------------------------- TCombat::TCombat(TguiMap* scene) :TSceneScript(scene) { uAttacker = NULL; uDefender = NULL; iAttackerKills = 0; iAttackerLoss = 0; bAttackerKilled = false; bDefenderKilled = false; iBuildingDamaged = 0; bBuildingDestroyed = false; } TCombat::TCombat( TUnit* attacker, TUnit* defender, TBuilding* b, int kills, int loss, bool ak, bool dk, int bdamaged, bool bdestroyed, TIntContainer* ah, TIntContainer* dh) :TSceneScript(attacker->map) { uAttacker = attacker; uDefender = defender; iAttackerKills = kills; iAttackerLoss = loss; // bAttackerBuilding = (TBuilding*)attacker->hexWhereIam->getProxy(ptBuilding); bTargetBuilding = b; if(bTargetBuilding)iBuildingDamaged = LIVES2DAMAGE(bTargetBuilding, bdamaged); else iBuildingDamaged = bdamaged; bBuildingDestroyed = bdestroyed; bAttackerKilled = ak; bDefenderKilled = dk; // if(ah)attacker_hidden = *ah; if(dh)defender_hidden = *dh; // if(attacker)aplayer = attacker->guiuiInfo.player; if(defender)dplayer = defender->guiuiInfo.player; else if(b) dplayer = b->guibiInfo.player; } void TCombat::findCombatantPosition(TCombatant* c, TUnitMemberPosition* target, TCombatant** enemy) { //cena za vzdalenost, nebo obsazenost float min_cost = FLT_MAX; float cost; float radius1 = SizeV2(c->ump.p2fDim.p)/2; float radius2; TCombatant *com = NULL; TUnitMemberPosition ump, best_ump, min_ratio_ump; //najdi jakekoliv nejblizsi na volne misto u nezabiteho obrance int indx = 0; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { //preskoc utocniky if( !(*cit).defender )continue; //preskoc mrtve if( (*cit).dead )continue; //preskoc vrazdene if( (*cit).slaughtered )continue; //polomer radius2 = SizeV2( (*cit).ump.p2fDim.p )/2; ump.p2fDim = (*cit).ump.p2fDim; //relativni pozice utocnika TVector rel_attack_pos = (TVector(c->ump.p2fPos) - TVector((*cit).ump.p2fPos)).norm()*(radius2 + radius1); //vsechny smery, vyber nejmensi kolizi float min_ratio = FLT_MAX; for(int j = 0; j < 8; j++) { //posun relativni pozici do polohy obrance ump.p2fPos = (*cit).ump.p2fPos; ump.p2fPos.x += rel_attack_pos.x; ump.p2fPos.y += rel_attack_pos.y; //a smer ump.p2fDir.x = -rel_attack_pos.x; ump.p2fDir.y = -rel_attack_pos.y; //vypocet kolize proti ostatnim, vyber nejvetsi float max_ratio = 0; float ratio; for(vector::iterator cit2 = combatants.begin(); cit2 != combatants.end(); cit2++) { //vyhnout se sam sobe if( &(*cit2) == c )continue; if( (*cit2).dead )continue; if( (*cit2).slaughtered )continue; //spocti kolizi ratio = intersectionRatio(&(ump), &((*cit2).ump)); if(ratio > max_ratio){ max_ratio = ratio; } } //srovnej s minimem if(max_ratio < min_ratio){ min_ratio = max_ratio; min_ratio_ump = ump; } //otoc relativni pozici rel_attack_pos.rotate(0,0,(float)M_PI/4); } //pokuta cost = DISTV2(min_ratio_ump.p2fPos.p, c->ump.p2fPos.p) + min_ratio*100; //porovnej s nejmensi if(cost < min_cost){ min_cost = cost; best_ump = min_ratio_ump; com = &(*cit); } indx++; } *target = best_ump; *enemy = com; } //TODO: lepe vector TCombat::findRandomVictimGroup(int size){ vector victims; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if( !(*cit).defender || (*cit).dead || (*cit).slaughtered ) continue; victims.push_back( &(*cit) ); if(victims.size()==size) break; } return victims; } TCombatant* TCombat::findRandomCombatant(int defender){ int range; int rnd; // if(defender && !uDefender)return NULL; if(!defender && !uAttacker)return NULL; if(defender) range = (int)uDefender->vMembers.size(); else range = (int)uAttacker->vMembers.size(); // rnd = (int)RAND(0, range); // for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { //je na spravne strane if((*cit).defender == defender) rnd--; else continue; //neni mrtvy a neni vrazden if((*cit).dead || (*cit).slaughtered) rnd--; else if(rnd<=0) return &(*cit); } return NULL; } void TCombat::findFormationPosition(TCombatant* c, TUnitMemberPosition* ump){ TUnitMemberPosition pos = c->ump; TUnitMemberPosition best_pos; //ziskat formaci TFormation *form; form = (c->defender?uDefender:uAttacker)->getFormation(); //projit vsechny pozice float min_ratio = FLT_MAX; for(int i = 0; i < form->vumpPositions_c; i++) { //vytvor pozici pos.p2fDir = form->vumpPositions[i].p2fDir;//(*ump_it).p2fDir; pos.p2fPos = form->vumpPositions[i].p2fPos;//(*ump_it).p2fPos; //testovat kolize proti vsem, zjisti nejvetsi pokutu float max_ratio = 0; float ratio; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { //preskoc sam sebe if(&(*cit) == c)continue; //spocti pokutu ratio = intersectionRatio(&pos, &(*cit).ump); if(ratio > max_ratio){ max_ratio = ratio; } } //pokud je nejvetsi pokuta lepsi nez dosud nalezena, tak pouzij pozici if(max_ratio < min_ratio){ min_ratio = max_ratio; best_pos = pos; } } // *ump = best_pos; } TCombatant* TCombat::getCombatant(TUnitMember* um) { for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if( (*cit).um == um ) return &(*cit); } return NULL; } int TCombat::attackers(){ int a = 0; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if( !(*cit).dead && !(*cit).slaughtered && !(*cit).finished && !(*cit).defender )a++; } return a; } int TCombat::defenders(){ int d = 0; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if( !(*cit).dead && !(*cit).slaughtered && !(*cit).finished && (*cit).defender )d++; } return d; } void TCombat::initCombatant(TCombatant* c, TUnitMember* um, int defender){ //spolecne c->um = um; um->getModelDim( &(c->ump.p2fDim) ); P3F pos, dir; um->getPosition(&pos); c->ump.p2fPos = pos.p2f; um->getDirection(&dir); c->ump.p2fDir = dir.p2f; c->attackpos = 0; c->defendpos = 0; c->slaughtered = 0; c->inbuilding = NULL; c->opponent = NULL; c->dead = 0; c->finished = 0; //rozdilne if(defender){ c->defender = 1; c->counterattack = 1; } else{ c->defender = 0; c->counterattack = 1; } } void TCombat::leavescript(TScriptedObject* so) { //preplanuj vsechny oponenty int live = 0; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { //umrtvit if( (*cit).um == (TUnitMember*)so ) { (*cit).dead = 1; (*cit).opponent = NULL; } //odnastavit if( ((*cit).opponent) && ((*cit).opponent->um == (TUnitMember*)so) ){ (*cit).opponent = NULL; (*cit).um->script(this, -1); } if( !(*cit).dead )live++; } SCLOG("TCombat::leavescript - live: %d, defenders: %d, attackers: %d\n", live, defenders(), attackers()); } TCombat::~TCombat(){ //viditelnost guimap->visibilityAltered_sensor(NULL, &attacker_hidden, aplayer); guimap->visibilityAltered_sensor(NULL, &defender_hidden, dplayer); //FIXME if( uAttacker && uAttacker->vMembers.size() && bAttackerKilled ){ SCLOG printf("ERROR in script execution. All attackers should be dead!!\n"); } if( uDefender && uDefender->vMembers.size() && bDefenderKilled ){ SCLOG printf("ERROR in script execution. All defenders should be dead!!\n"); } //utocnik zemrel if( uAttacker && uAttacker->vMembers.size()==0 ){ if(bAttackerBuilding)bAttackerBuilding->hangDownFlag(); SCLOG("TCombat::~TCombat - attacker unit eliminated\n"); guimap->unitRemoved_sensor(uAttacker); gui::TUnit::uninstallUnit(guimap, uAttacker->guiuiInfo.livingunit, false); } //obrance zemrel if( uDefender && uDefender->vMembers.size()==0 ){ if(bTargetBuilding)bTargetBuilding->hangDownFlag(); SCLOG("TCombat::~TCombat - defender unit eliminated\n"); guimap->unitRemoved_sensor(uDefender); gui::TUnit::uninstallUnit(guimap, uDefender->guiuiInfo.livingunit, false); } //budova znicena if( bBuildingDestroyed && bTargetBuilding ){ SCLOG("TCombat::~TCombat - defender building eliminated\n"); } // SCLOG("TCombat::~TCombat - deleting combat script instance\n"); SCLOG("ak: %d, al: %d, ak: %d, dk: %d, bd: %d, bdam: %d\n", iAttackerKills, iAttackerLoss, (int)bAttackerKilled, (int)bDefenderKilled, iBuildingDamaged, (int)bBuildingDestroyed); } int TCombat::getStatusMsg(char* buff, int size){ return snprintf(buff, size, "GenericCombatScript: combatants: %d(attackers: %d, defenders %d)", (int)combatants.size(), attackers(), defenders()); } //TCloseCombat //----------------------------------------------------------------------------- #define COMBAT_IDLE 500 #define COMBAT_DUELING 3000 #define COMBAT_SLAUGHTERING 1500 #define COMBAT_DEFENDING_FIRE_RELOAD 5000 #define INDIVIDUAL(a) ((a)->unit->guiuiInfo.formation==ftIndividualFormation) #define DEFENDING_INDIVIDUAL_SLAUGHTERED ( (iAttackerKills==1) && bDefenderKilled ) #define ATTACKING_INDIVIDUAL_SLAUGHTERED ( (iAttackerLoss==1) && bAttackerKilled ) void TCloseCombat::decision(TScriptedObject* so) { TUnitMemberPosition ump; TCombatant* c = getCombatant((TUnitMember*)so); TCombatant* c2; int ktime = KTime(); assert(c); //======================================== //=== Nechat se zabit a opustit scenar === //======================================== if(c->slaughtered){ c->um->die(); leavescript(so); } //====================== //=== Opustit scenar === //====================== else if(c->finished){ leavescript(so); } //===================== //=== ROLE: obrance === //===================== else if( c->defender ){ //========================================= //=== Jeste nejsme v obrannych pozicich === //========================================= if(!c->defendpos){ //presun do nejblizsi volne obranne pozice findFormationPosition(c,&ump); c->ump = ump; c->um->go(&(ump.p2fPos), &(ump.p2fDir)); c->defendpos = 1; //preplanuj po konci pochodu c->um->script(this, -1); } //=========================== //=== Strelecky protiutok === //=========================== else if( (c->counterattack || iAttackerLoss) && DISTANT(uDefender->guiuiInfo.attackType) ){ c2 = findRandomCombatant(0); // --------------------------- // --- neni po kom strilet --- // --------------------------- if(!c2){ //TODO: vystrel smerem c->um->script(this, ktime+COMBAT_IDLE); } else { // -------------------------- // --- strelba - katapult --- // -------------------------- if( uAttacker->guiuiInfo.attackType == atCatapultAttack ){ } // ----------------------------- // --- strelba - luk, kouzlo --- // ----------------------------- else{ TDistant_Attack* da = c->um->fire(c2->um); c->um->script(this, c->um->iLastAnimationEnd + COMBAT_DEFENDING_FIRE_RELOAD); float random_factor = RAND(0,1); //------------- //--- zabij --- //------------- if( iAttackerLoss>0 && random_factor>0.9f && !(bAttackerKilled && attackers()==1) ){ //preplanuj obet na dobu dopadu strely c2->slaughtered = (!INDIVIDUAL(c2->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; c2->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); // iAttackerLoss--; } } }//else //povinny protiutok c->counterattack = 0; } //=========================================== //=== nebojuje ale souboj jeste neskoncil === //=========================================== else if( (!c->opponent) && (attackers()) ){ c->um->stopAllAnimations(); c->um->script(this, ktime+COMBAT_IDLE); } //================================= //=== nebojuje a souboj skoncil === //================================= else if( (!c->opponent) && (!attackers()) ){ c->um->stopAllAnimations(); c->finished = 1; c->um->script(this, -1); } //============================== //=== naplanuj dalsi kolecko === //============================== else{ c->um->script(this, ktime+COMBAT_IDLE); } } //===================== //=== ROLE: utocnik === //===================== else{ //======================= //=== Pokracuj v boji === //======================= if( ((iAttackerKills + iAttackerLoss) > 0) && c->opponent && c->opponent->slaughtered){ c->um->fight(c->opponent->um); int slaughtering_len = COMBAT_SLAUGHTERING; //preplanuj c->um->script(this, ktime + slaughtering_len); } //============= //=== Zabij === //============= else if( ((iAttackerKills + iAttackerLoss) > 0) && c->opponent && !c->opponent->slaughtered){ c->um->fight(c->opponent->um); c->opponent->um->fight(c->um); //---------------------------------------------------------- //--- specialni pripad, posledni dva se zabijou najednou --- //---------------------------------------------------------- if( iAttackerKills==1 && iAttackerLoss==1 && attackers()==1 && defenders()==1 ) { c->opponent->slaughtered = (!INDIVIDUAL(c->opponent->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; iAttackerKills--; // c->slaughtered = (!INDIVIDUAL(c->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; iAttackerLoss--; // c->um->script(this, ktime + COMBAT_DUELING); c->opponent->um->script(this, ktime + COMBAT_DUELING); } //--------------------------------------------------------------------- //--- utocnik vyhral a obrance mam zasobu na splneni dalsich zabiti --- //--------------------------------------------------------------------- else if( (iAttackerKills > iAttackerLoss) ) { c->opponent->slaughtered = (!INDIVIDUAL(c->opponent->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; c->opponent->um->script(this, ktime + COMBAT_DUELING); // c->um->script(this, ktime + COMBAT_DUELING); // iAttackerKills--; } //--------------------------------------------------------------------- //--- obrance vyhral a utocnik mam zasobu na splneni dalsich zabiti --- //--------------------------------------------------------------------- else if( (iAttackerKills <= iAttackerLoss) ) { c->slaughtered = (!INDIVIDUAL(c->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; c->um->script(this, ktime + COMBAT_DUELING); // c->opponent->um->script(this, ktime + COMBAT_DUELING); // iAttackerLoss--; } } //======================== //=== Najdi protivnika === //======================== else if( ((iAttackerKills + iAttackerLoss)>0 || (c->counterattack && defenders())) && !c->opponent ){ findCombatantPosition(c, &ump, &c2); c->ump = ump; c->opponent = c2; //zastav c->um->stopAllAnimations(); //jdi c->um->go(&(ump.p2fPos), &(ump.p2fDir)); c->um->script(this, -1); c->counterattack = 0; } //============= //=== Ustup === //============= else if( (iAttackerKills + iAttackerLoss) == 0 ){ //stahne se na nejblizsi volne obrane misto findFormationPosition(c,&ump); c->ump = ump; //zastav animace c->um->stopAllAnimations(); //ustup c->um->go(&(ump.p2fPos), &(ump.p2fDir)); c->finished = 1; c->um->script(this, -1); } }//else } TCloseCombat::TCloseCombat( TUnit* attacker, TUnit* defender, int kills_count, int losses, bool ak, bool dk, TIntContainer* ah, TIntContainer* dh) :TCombat(attacker, defender, NULL, kills_count, losses, ak, dk, 0, false, ah, dh) { TCombatant com; //obranci for(vunitmember::iterator dit = uDefender->vMembers.begin(); dit != uDefender->vMembers.end(); dit++) { initCombatant(&com, *dit, 1); combatants.push_back(com); } //utocnici for(vunitmember::iterator ait = uAttacker->vMembers.begin(); ait != uAttacker->vMembers.end(); ait++) { initCombatant(&com, *ait, 0); combatants.push_back(com); } //pocatecni rozhodnuti for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { decision( (TScriptedObject*)(*cit).um ); } } //TDistantCombat //----------------------------------------------------------------------------- #define DISTANT_DYING 500 #define DISTANT_IDLE 500 #define DISTANT_RELOAD 1000 #define DISTANT_HIT_TRESHOLD 0.7f void TDistantCombat::decision(TScriptedObject* so){ TUnitMemberPosition ump; TCombatant *c, *c2; int ktime = KTime(); //===================== //=== ROLE: budova === //===================== if(so == (TScriptedObject*)bTargetBuilding){ if(bBuildingDestroyed && iBuildingDamaged==0) buildingDestroyed(); } //====================== //=== ROLE: bojovnik === //====================== else { c = getCombatant((TUnitMember*)so); assert(c); //===================== //=== Konec skriptu === //===================== if(c->finished){ leavescript(so); } //======================= //=== Nechat se zabit === //======================= else if(c->slaughtered){ c->um->die( ktime+(int)RAND(0,DISTANT_DYING) ); leavescript(so); } //===================== //=== ROLE: obrance === //===================== else if(c->defender){ //--------------------------------- //--- nebojuje a souboj skoncil --- //--------------------------------- if( !attackers() ){ c->um->stopAllAnimations(); c->finished = 1; c->um->script(this, -1); } //--------------------- //--- dalsi kolecko --- //--------------------- else { c->um->script(this, ktime+DISTANT_IDLE); } } //===================== //=== ROLE: utocnik === //===================== else{ //============================= //=== Jdi na utocnou pozici === //============================= if( !c->attackpos ){ //poloha pro utok findFormationPosition(c,&ump); //pokud je v otevrene budove neformuje se if( uAttacker->hexWhereIam->getProxy(ptBuilding) ) ump.p2fPos = c->ump.p2fPos; // c->ump = ump; c->um->go(&(ump.p2fPos), &(ump.p2fDir)); c->attackpos = 1; //preplanuj po konci pochodu c->um->script(this, -1); } //========================= //=== Vystrel na budovu === //========================= else if( ((iBuildingDamaged > 0) || c->counterattack) && bTargetBuilding ){ // ----------------------- // --- utok - katapult --- // ----------------------- if( uAttacker->guiuiInfo.attackType == atCatapultAttack ){ TDistant_Attack* da = c->um->fire(bTargetBuilding); c->um->script(this, c->um->iLastAnimationEnd); // if(iBuildingDamaged){ while(iBuildingDamaged){ bTargetBuilding->sufferDamage( ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); // bTargetBuilding->gotHit( ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); iBuildingDamaged--; } bTargetBuilding->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio)); } if(iAttackerKills){ //najdi hloucek velikosti pocty ztrat vector vic = findRandomVictimGroup(iAttackerKills); vector::iterator it = vic.begin(); //vystrel nekam tam TDistant_Attack* da = c->um->fire( (*it)->um ); c->um->script(this, c->um->iLastAnimationEnd); //------------- //--- zabij --- //------------- while(iAttackerKills){ it = vic.begin(); c2 = *it; c2->slaughtered = (!INDIVIDUAL(c2->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; if(c2->slaughtered) vic.erase(it); c2->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); iAttackerKills--; } } } // --------------------- // --- utok - kouzlo --- // --------------------- else if( uAttacker->guiuiInfo.attackType == atMagicMissileAttack ){ TDistant_Attack* da = c->um->fire( bTargetBuilding ); c->um->script(this, c->um->iLastAnimationEnd + DISTANT_RELOAD); // if(iBuildingDamaged){ // int hits = (int)ROUND( RAND(0, MIN(6, iBuildingDamaged)) ); while(hits){ // bTargetBuilding->sufferDamage( ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); iBuildingDamaged--; hits--; // bTargetBuilding->gotHit( ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); } bTargetBuilding->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio)); } } // -------------------------- // --- utok - luk, kouzlo --- // -------------------------- else{ TDistant_Attack* da = c->um->fire(bTargetBuilding); c->um->script(this, c->um->iLastAnimationEnd + DISTANT_RELOAD); // if(iBuildingDamaged){ // bTargetBuilding->sufferDamage( ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); iBuildingDamaged--; // bTargetBuilding->gotHit( ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); if(!iBuildingDamaged) bTargetBuilding->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio)); } }//attack type //bylo vystreleno aspon jednou c->counterattack = 0; } //========================== //=== Vystrel na panacky === //========================== else if( (iAttackerKills > 0) || c->counterattack ){ c2 = findRandomCombatant(1); // --------------------------- // --- neni po kom strilet --- // --------------------------- if(!c2) { //TODO: vystrel smerem c->um->script(this, ktime+COMBAT_IDLE); } else { // ----------------------- // --- utok - katapult --- // ----------------------- if( uAttacker->guiuiInfo.attackType == atCatapultAttack ){ //najdi hloucek velikosti pocty ztrat vector vic = findRandomVictimGroup(iAttackerKills); vector::iterator it = vic.begin(); //vystrel nekam tam TDistant_Attack* da = c->um->fire( (*it)->um ); c->um->script(this, c->um->iLastAnimationEnd); //------------- //--- zabij --- //------------- while(iAttackerKills){ it = vic.begin(); c2 = *it; c2->slaughtered = (!INDIVIDUAL(c2->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; if(c2->slaughtered) vic.erase(it); c2->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); iAttackerKills--; } } // --------------------- // --- utok - kouzlo --- // --------------------- else if( uAttacker->guiuiInfo.attackType == atMagicMissileAttack ){ // int hits = (int)ROUND( RAND(0, MIN(6, iAttackerKills)) ); //najdi hloucek velikosti pocty ztrat vector vic = findRandomVictimGroup(hits); vector::iterator it = vic.begin(); //vystrel nekam tam TDistant_Attack* da = c->um->fire( (*it)->um ); c->um->script(this, c->um->iLastAnimationEnd + DISTANT_RELOAD); //------------- //--- zabij --- //------------- while(hits){ it = vic.begin(); c2 = *it; c2->slaughtered = (!INDIVIDUAL(c2->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; if(c2->slaughtered) vic.erase(it); c2->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); iAttackerKills--; hits--; } } // ------------------ // --- utok - luk --- // ------------------ else{ TDistant_Attack* da = c->um->fire(c2->um); c->um->script(this, c->um->iLastAnimationEnd + DISTANT_RELOAD); float random_factor = RAND(0,1); //------------- //--- zabij --- //------------- if(random_factor > DISTANT_HIT_TRESHOLD && iAttackerKills){ //preplanuj obet na dobu dopadu strely c2->slaughtered = (!INDIVIDUAL(c2->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; c2->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); // iAttackerKills--; } }//attack type } //bylo vystreleno aspon jednou c->counterattack = 0; } //============= //=== Konec === //============= else{ c->um->stopAllAnimations(); c->finished = 1; c->um->script(this, -1); } }//else }//else budova } void TDistantCombat::buildingDestroyed() { //zrus vazbu na budovu for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if((*cit).inbuilding == bTargetBuilding) (*cit).inbuilding = NULL; } //zrus budovu guimap->buildingRemoved_sensor(bTargetBuilding); bTargetBuilding->bc->removeAllActions(); bTargetBuilding->destroyBuilding(); bTargetBuilding->remove(); bTargetBuilding = NULL; bBuildingDestroyed = 0; //zrus jednotku uvnitr if(uDefender) { //vyhod a zabij obrance for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if((*cit).defender){ (*cit).dead = 1; (*cit).um->setTransparency(1); (*cit).um->flyAway(); leavescript((TScriptedObject* )(*cit).um); } }//for combatants }//if } TDistantCombat::TDistantCombat( TUnit* attacker, TUnit* defender, TBuilding* b, int kills, int loss, bool ak, bool dk, int bdamaged, bool bdestroyed, TIntContainer* ah, TIntContainer* dh) :TCombat(attacker, defender, b, kills, loss, ak, dk, bdamaged, bdestroyed, ah, dh) { TCombatant com; //obranci if(uDefender){ for(vunitmember::iterator dit = uDefender->vMembers.begin(); dit != uDefender->vMembers.end(); dit++) { initCombatant(&com, *dit, 1); combatants.push_back(com); } } //utocnici for(vunitmember::iterator ait = uAttacker->vMembers.begin(); ait != uAttacker->vMembers.end(); ait++) { initCombatant(&com, *ait, 0); combatants.push_back(com); } //pocatecni rozhodnuti for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { decision( (TScriptedObject*)(*cit).um ); } } //TOpenBuildingCombat //----------------------------------------------------------------------------- #define OPENBUILDING_COMBAT_IDLE 500 #define OPENBUILDING_COMBAT_DUELING 3000 #define OPENBUILDING_COMBAT_SLAUGHTERING 1500 #define OPENBUILDING_COMBAT_RELOAD 5000 void TOpenBuildingCombat::buildingDestroyed() { //zrus vazbu na budovu for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if((*cit).inbuilding == bTargetBuilding) (*cit).inbuilding = NULL; if((*cit).defender) (*cit).um->flyAway(); } //zrus budovu guimap->buildingRemoved_sensor(bTargetBuilding); bTargetBuilding->bc->removeAllActions(); bTargetBuilding->destroyBuilding(); bTargetBuilding->remove(); bTargetBuilding = NULL; bBuildingDestroyed = 0; } void TOpenBuildingCombat::DEFENDER_decision(TCombatant* c){ TCombatant* c2; int ktime = KTime(); //========================================= //=== jeste nejsme v obrannych pozicich === //========================================= if(!c->defendpos){ //presun do nejblizsi volne obranne pozice P2F p, d; uAttacker->getUnitPos(&p, &d); c->ump.p2fDir = (TVector(p) - TVector(c->ump.p2fPos)).toP2F(); c->um->go(&(c->ump.p2fPos), &(c->ump.p2fDir)); c->defendpos = 1; //preplanuj po konci pochodu c->um->script(this, -1); } //=========================== //=== strelecky protiutok === //=========================== else if( (iAttackerLoss>0 || c->counterattack) && DISTANT(uDefender->guiuiInfo.attackType) ){ c2 = findRandomCombatant(0); //==================== //=== neni na koho === //==================== if(!c2) { //TODO: vystrel smerem c->um->script(this, ktime+OPENBUILDING_COMBAT_IDLE); } //============= //=== zabij === //============= else if( iAttackerLoss > 0 && !(attackers()==1 && iAttackerKills) ) { //----------------------- //--- utok - katapult --- //----------------------- if( uAttacker->guiuiInfo.attackType == atCatapultAttack ){ } //-------------------------------- //--- utok - lucistnik, kouzlo --- //-------------------------------- else{ //vystrel TDistant_Attack* da = c->um->fire(c2->um); c->um->script(this, c->um->iLastAnimationEnd + OPENBUILDING_COMBAT_RELOAD); //preplanuj obet na dobu dopadu strely c2->slaughtered = (!INDIVIDUAL(c2->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; c2->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); // iAttackerLoss--; } } //=============== //=== nezabij === //=============== else { TDistant_Attack* da = c->um->fire(c2->um); c->um->script(this, c->um->iLastAnimationEnd + OPENBUILDING_COMBAT_RELOAD); } //povinny protiutok c->counterattack = 0; } //=========================================== //=== nebojuje ale souboj jeste neskoncil === //=========================================== else if( (!c->opponent) && (attackers()) ){ c->um->stopAllAnimations(); c->um->script(this, ktime+OPENBUILDING_COMBAT_IDLE); } //================================= //=== nebojuje a souboj skoncil === //================================= else if( (!c->opponent) && (!attackers()) ){ c->um->stopAllAnimations(); c->finished = 1; c->um->script(this, -1); } //============================== //=== naplanuj dalsi kolecko === //============================== else{ c->um->script(this, ktime+OPENBUILDING_COMBAT_IDLE); } } void TOpenBuildingCombat::ATTACKER_decision(TCombatant* c){ TUnitMemberPosition ump; TCombatant* c2; int ktime = KTime(); //======================= //=== pokracuj v boji === //======================= if( ((iAttackerKills + iAttackerLoss + iBuildingDamaged) > 0) && ((c->opponent && c->opponent->slaughtered)||(c->attackpos && iBuildingDamaged==0)) ){ if(c->opponent)c->um->fight(c->opponent->um); else c->um->fight(bTargetBuilding); c->um->script(this, ktime + OPENBUILDING_COMBAT_SLAUGHTERING); c->opponent=NULL; c->attackpos=0; } //================= //=== najdi cil === //================= else if( ((iAttackerKills + iAttackerLoss + iBuildingDamaged)>0 || (c->counterattack && defenders()) ) && !(c->opponent || c->attackpos) ){ //pomocne prommenne P2F route_buff[20]; P2F tangent_buff[20]; int beg = 0; float urad = SizeV2(c->ump.p2fDim.p)/2; //=============================== //=== rozhodni se, kam pujdes === //=============================== float rand_factor = 0; float border = 0.5f; if( (iAttackerKills + iAttackerLoss)>0 && iBuildingDamaged>0 ){ rand_factor = RAND(0,1); border = iBuildingDamaged/(float)(iAttackerKills + iAttackerLoss); } else if( (iAttackerKills + iAttackerLoss)>0 || !bTargetBuilding ) rand_factor = 1; else if( iBuildingDamaged>0 ) rand_factor = 0; //=========================== //=== najdi si protivnika === //=========================== if(rand_factor > border){ findCombatantPosition(c, &ump, &c2); // P2F out_dir = ( TVector(ump.p2fPos) - TVector(c->ump.p2fPos) ).toP2F(); //====================== //=== vylez z budovy === //====================== if(c->inbuilding && bAttackerBuilding == c->inbuilding){ beg += bAttackerBuilding->generateRouteOutside(&out_dir, route_buff + beg, tangent_buff + beg, 20, urad); c->inbuilding = NULL; if( CLOSEDBUILDING(bAttackerBuilding) ) c->um->fadein(); } //====================== //=== vlez do budovy === //====================== if(c->inbuilding != bTargetBuilding ){ beg += bTargetBuilding->generateRouteInside(&out_dir, route_buff + beg, tangent_buff + beg, 20, urad); c->inbuilding = bTargetBuilding; } //pridej cilove misto route_buff[beg] = ump.p2fPos; tangent_buff[beg] = ump.p2fDir; beg++; // c->ump = ump; c->opponent = c2; } //======================= //=== najdi si budovu === //======================= else{ // P2F dir, pos; P3F ap; c->um->getPosition(&ap); //============================================== //=== vylez z budovy & jdi na utocnou pozici === //============================================== if( c->inbuilding && c->inbuilding!=bTargetBuilding ){ P2F tb, out_dir; //zviditelni se if( CLOSEDBUILDING(bAttackerBuilding) ) c->um->fadein(); //smer utoku bTargetBuilding->getPosition(&tb); out_dir = ( TVector(tb) - TVector(ap) ).toP2F(); beg += bAttackerBuilding->generateRouteOutside(&out_dir, route_buff, tangent_buff, 10, urad); //najdi utocnou pozici bTargetBuilding->getAttackPosition(&(route_buff[beg-1]), &dir, &pos); c->inbuilding = NULL; } //============================= //=== jdi na utocnou pozici === //============================= else{ bTargetBuilding->getAttackPosition(&(ap.p2f), &dir, &pos); } //pripoj pozici k ceste route_buff[beg] = pos; tangent_buff[beg] = dir; beg++; c->attackpos = 1; } //go c->um->go(beg, route_buff, tangent_buff); c->um->script(this, -1); } //======================== //=== zautoc na budovu === //======================== else if( ( iBuildingDamaged > 0 || c->counterattack ) && c->attackpos ){ c->um->fight(bTargetBuilding); c->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); c->attackpos = 0; c->counterattack = 0; // if(iBuildingDamaged > 0){ bTargetBuilding->sufferDamage(ktime); iBuildingDamaged--; } if( bBuildingDestroyed )bTargetBuilding->script(this, -1); } //========================== //=== zautoc na jednotku === //========================== else if( ( (iAttackerKills + iAttackerLoss)>0 || c->counterattack ) && c->opponent && !c->opponent->slaughtered ){ c->um->fight(c->opponent->um); c->opponent->um->fight(c->um); //============================================= //=== zabiji se navzajem - specialni pripad === //============================================= if( iAttackerKills==1 && iAttackerLoss==1 && defenders()==1 && attackers()==1 ) { c->opponent->slaughtered = (!INDIVIDUAL(c->opponent->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; iAttackerKills--; // c->slaughtered = (!INDIVIDUAL(c->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; iAttackerLoss--; // c->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); c->opponent->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); } //==================================================================== //=== utocnik vyhral a obrance ma zasobu na splneni dalsich zabiti === //==================================================================== else if( iAttackerKills > iAttackerLoss ) { c->opponent->slaughtered = (!INDIVIDUAL(c->opponent->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; c->opponent->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); // c->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); // iAttackerKills--; } //===================================================================== //=== obrance vyhral a utocnik mam zasobu na splneni dalsich zabiti === //===================================================================== else if( iAttackerLoss > 0 ) { c->slaughtered = (!INDIVIDUAL(c->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; c->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); // c->opponent->um->script(this, ktime + OPENBUILDING_COMBAT_DUELING); // iAttackerLoss--; } //==================== //=== preplanovani === //==================== else { c->um->script(this, ktime + OPENBUILDING_COMBAT_IDLE); } //povinny utok c->counterattack = 0; c->opponent=NULL; if( bBuildingDestroyed )bTargetBuilding->script(this, -1); } //============= //=== ustup === //============= else if( (iAttackerKills + iAttackerLoss + iBuildingDamaged) == 0 ){ if( bTargetBuilding && bBuildingDestroyed )bTargetBuilding->script(this, -1); //stahne se na nejblizsi volne obrane misto findFormationPosition(c,&ump); // P2F route_buff[20]; P2F tangent_buff[20]; int beg = 0; float urad = SizeV2(c->ump.p2fDim.p)/2; P2F out_dir = ( TVector(ump.p2fPos) - TVector(c->ump.p2fPos) ).toP2F(); //====================== //=== vylez z budovy === //====================== if(c->inbuilding){ beg += c->inbuilding->generateRouteOutside(&out_dir, route_buff + beg, tangent_buff + beg, 20, urad); c->inbuilding = NULL; } //====================== //=== vlez do budovy === //====================== if(bAttackerBuilding){ beg += bAttackerBuilding->generateRouteInside(&out_dir, route_buff + beg, tangent_buff + beg, 20, urad); c->inbuilding = bAttackerBuilding; if( OPENBUILDING(bAttackerBuilding) ){ ((TOpenStructure*)bAttackerBuilding)->findPosition(&(c->ump.p2fDim), &ump.p2fPos); } } //pridej cilove misto route_buff[beg] = ump.p2fPos; tangent_buff[beg] = ump.p2fDir; beg++; //zastav animace c->um->stopAllAnimations(); //ustup c->ump = ump; c->um->go(beg, route_buff, tangent_buff); if(bAttackerBuilding && CLOSEDBUILDING(bAttackerBuilding)) c->um->fadeout(); c->finished = 1; c->um->script(this, -1); } } void TOpenBuildingCombat::BUILDING_decision() { //====================== //=== budova znicena === //====================== if(bBuildingDestroyed && (iAttackerKills + iAttackerLoss + iBuildingDamaged)==0) { int fi = 0; for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if(!(*cit).finished && !(*cit).dead && !(*cit).defender) fi++; } //ustupuje posledni if( fi <= 1 ){ buildingDestroyed(); } } } void TOpenBuildingCombat::decision(TScriptedObject* so) { //==================== //=== ROLE: budova === //==================== if(((TBuilding*)so) == bTargetBuilding) { BUILDING_decision(); } else { //====================== //=== ROLE: bojovnik === //====================== TCombatant* c = getCombatant((TUnitMember*)so); assert(c); //============= //=== konec === //============= if(c->finished){ leavescript(so); } //======================= //=== nechat se zabit === //======================= else if(c->slaughtered){ c->um->die(); leavescript(so); } //===================== //=== ROLE: obrance === //===================== else if( c->defender ) { DEFENDER_decision(c); } //===================== //=== ROLE: utocnik === //===================== else { ATTACKER_decision(c); } }//else } TOpenBuildingCombat::TOpenBuildingCombat(TUnit* attacker, TUnit* defender, TBuilding* b, int kills, int loss, bool ak, bool dk, int bdamaged, bool bdestroyed, TIntContainer* ah, TIntContainer* dh) :TCombat(attacker, defender, b, kills, loss, ak, dk, bdamaged, bdestroyed, ah, dh) { TCombatant com; //obranci if(uDefender) { for(vunitmember::iterator dit = uDefender->vMembers.begin(); dit != uDefender->vMembers.end(); dit++) { initCombatant(&com, *dit, 1); com.inbuilding = bTargetBuilding; combatants.push_back(com); } } //utocnici for(vunitmember::iterator ait = uAttacker->vMembers.begin(); ait != uAttacker->vMembers.end(); ait++) { initCombatant(&com, *ait, 0); com.inbuilding = bAttackerBuilding; combatants.push_back(com); } //pocatecni rozhodnuti for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { decision( (TScriptedObject*)(*cit).um ); } //pocatecni rozhodnuti budovy if(bTargetBuilding) decision( (TScriptedObject*)bTargetBuilding ); //zrus rozmisteni v budove if( bAttackerBuilding && OPENBUILDING(bAttackerBuilding) ){ ((TOpenStructure*)bAttackerBuilding)->clearPositions(); } } //TBuildingAttack //----------------------------------------------------------------------------- #define BUILDINGATTACK_REALOAD 800 #define BUILDINGATTACK_HIT_RESPONSE 1000 #define BUILDINGATTACK_DAMAGE_TRESHOLD 0.2f #define BUILDINGATTACK_HIT_TRESHOLD 0.7f TBuildingAttack::TBuildingAttack( TUnit* attacker, TUnit* defender, TBuilding* b, int kills, int loss, bool ak, bool dk, int bdamaged, bool bdestroyed, TIntContainer* ah, TIntContainer* dh) :TCombat(attacker, defender, b, kills, loss, ak, dk, bdamaged, bdestroyed, ah, dh) { TCombatant com; //obranci while(iAttackerKills && uDefender) { vunitmember::iterator dit = uDefender->vMembers.begin(); TUnitMember* um = (TUnitMember*)(*dit); if( !INDIVIDUAL(um) || DEFENDING_INDIVIDUAL_SLAUGHTERED ) delete *dit; iAttackerKills--; } //utocnici for(vunitmember::iterator ait = uAttacker->vMembers.begin(); ait != uAttacker->vMembers.end(); ait++) { initCombatant(&com, *ait, 0); com.inbuilding = bAttackerBuilding; // combatants.push_back(com); } //pocatecni rozhodnuti for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { decision( (TScriptedObject*)(*cit).um ); } //prvni rozhodnuti budovy decision( (TScriptedObject*)bTargetBuilding ); } void TBuildingAttack::buildingDestroyed(){ //zrus jednotku uvnitr if(uDefender){ bTargetBuilding->hangDownFlag(); for(vunitmember::iterator m_it = uDefender->vMembers.begin(); m_it != uDefender->vMembers.end(); m_it = uDefender->vMembers.begin()) { (*m_it)->setTransparency(1); (*m_it)->flyAway(); } } //zrus budovu guimap->buildingRemoved_sensor(bTargetBuilding); bTargetBuilding->destroyBuilding(); bTargetBuilding->remove(); bTargetBuilding = NULL; bBuildingDestroyed = 0; } void TBuildingAttack::decision(TScriptedObject* so){ P2F control_points[10]; P2F tangents[10]; int route_len = 0; P2F dir, pos; TCombatant *c,*c2; int ktime = KTime(); //==================== //=== ROLE: budova === //==================== if( so == (TScriptedObject*)bTargetBuilding ) { //----------------------------------------------------------------------- //--- ma nekoho zabit, ale nesmi zabit posledniho pokud ma byt zabyta --- //----------------------------------------------------------------------- if( iAttackerLoss > 0 && !(iAttackerLoss==1 && attackers()==1 && bBuildingDestroyed) ){ //strelba sipu(z budovy se vzdycky protiutoci sipama) c = findRandomCombatant(0); if(c){ TDistant_Attack* da = bTargetBuilding->defensiveFire(c->um); //preplanuj na dalsi strelbu bTargetBuilding->script(this, ktime + BUILDINGATTACK_REALOAD); //zabij c->slaughtered = (!INDIVIDUAL(c->um)) || ATTACKING_INDIVIDUAL_SLAUGHTERED; c->um->script(this, ROUND(da->iActivationTime + da->iDur/da->fTimeRatio) ); // iAttackerLoss--; } } //---------------------- //--- ma vybouchnout --- //---------------------- else if(bBuildingDestroyed && iBuildingDamaged==0 ){ buildingDestroyed(); } } //====================== //=== ROLE: bojovnik === //====================== else { c = getCombatant((TUnitMember*)so); assert(c); //ma byt zabit if( c->slaughtered ){ //umri c->um->die(); leavescript(so); } else if(c->finished){ leavescript(so); } //================================ //=== ROLE: bojovnik - utocnik === //================================ else if( !c->defender ){ //============================= //==== JE NA UTOCNE POZICI ==== //============================= if(c->attackpos){ //----------------------------- //--- umre utocnik i budova --- //----------------------------- if( bBuildingDestroyed && iAttackerLoss==1 && attackers()==1 ){ //zabitej utocnik c->slaughtered = 1; c->um->script(this, 500 ); iAttackerLoss--; // bTargetBuilding->script(this, 500); iBuildingDamaged = 0; } //-------------------- //--- mam zautocit --- //-------------------- else if( ((iAttackerKills+iBuildingDamaged) > 0 || c->counterattack) && bTargetBuilding ){ c->um->fight(bTargetBuilding); c->um->script(this, c->um->iLastAnimationEnd); //---------------------------- //--- ma poskodit jednotku --- //---------------------------- if( iAttackerKills > 0 ){ c2 = findRandomCombatant(1); if(c2){ c2->slaughtered = (!INDIVIDUAL(c2->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; c2->um->script(this, c->um->iLastAnimationEnd); } iAttackerKills--; } //-------------------------- //--- ma poskodit budovu --- //-------------------------- else if(iBuildingDamaged > 0){ //vysledek utoku float rnd = RAND(0,1); //poskod budovu if(iBuildingDamaged > 0 && rnd < BUILDINGATTACK_DAMAGE_TRESHOLD){ bTargetBuilding->sufferDamage(ktime); bTargetBuilding->script(this, c->um->iLastAnimationEnd); iBuildingDamaged--; } //zasahni else{ bTargetBuilding->gotHit(); } } //povinny utok c->counterattack = 0; } //------------------------------- //--- nema poskodit -> navrat --- //------------------------------- else{ //vrat se do budovy if(bAttackerBuilding){ P2F ab, in_dir; P3F umpos; float rad; // bAttackerBuilding->getPosition(&ab); c->um->getPosition(&umpos); in_dir = ( TVector(ab) - TVector(umpos) ).toP2F(); rad = SizeV2(c->ump.p2fDim.p)/2; // route_len += bAttackerBuilding->generateRouteInside(&in_dir, control_points, tangents, 10, rad); } //pripoj polohu ve formaci control_points[route_len] = c->ump.p2fPos; tangents[route_len] = c->ump.p2fDir; route_len++; //jdi c->um->stopAllAnimations(); c->um->go(route_len, control_points, tangents); if( bAttackerBuilding && CLOSEDBUILDING(bAttackerBuilding) ) c->um->fadeout(); c->attackpos = 0; c->finished = 1; c->um->script(this, -1); } } //=============================== //==== NENI NA UTOCNE POZICI ==== //=============================== else if(!c->attackpos){ P3F ap; c->um->getPosition(&ap); //vylez z budovy if( c->inbuilding ){ P2F tb, out_dir; float rad = SizeV2(c->ump.p2fDim.p); //zviditelni se if( CLOSEDBUILDING(bAttackerBuilding) ) c->um->fadein(); //smer utoku bTargetBuilding->getPosition(&tb); out_dir = ( TVector(tb) - TVector(ap) ).toP2F(); route_len += bAttackerBuilding->generateRouteOutside(&out_dir, control_points, tangents, 10, rad); //najdi utocnou pozici bTargetBuilding->getAttackPosition(&(control_points[route_len-1]), &dir, &pos); } else{ bTargetBuilding->getAttackPosition(&(ap.p2f), &dir, &pos); } //pripoj pozici k ceste control_points[route_len] = pos; tangents[route_len] = dir; route_len++; //jdi c->um->go(route_len, control_points, tangents); c->attackpos = 1; //preplanuj c->um->script(this, -1); }//else if attackpos }//if !defender }//else combatant } //TBlastAttack //----------------------------------------------------------------------------- #define BLASTATTACK_FLYAWAY_TRESHOLD 0.5f #define BLASTATTACK_COUNTERATTACK_TRESHOLD 0.1f #define BLASTATTACK_IDLE 500 #define BLASTATTACK_REALOAD 200 #define BLASTATTACK_EXPLOSION_DUR 10000 #define BLASTATTACK_REACTION_DEALAY 2000 void TBlastAttack::decision(TScriptedObject* so){ int ktime = KTime(); TUnitMemberPosition ump; TCombatant* c; TCombatant* c2; //==================== //=== ROLE: budova === //==================== if( so == (TScriptedObject*)bTargetBuilding ){ //======================================================================= //=== Ma nekoho zabit, ale nesmi zabit posledniho pokud ma byt zabyta === //======================================================================= if( (iAttackerLoss > 0) && CLOSEDBUILDING(bTargetBuilding) && !(iAttackerLoss==1 && attackers()==1 && bBuildingDestroyed) ){ //strelba c = findRandomCombatant(0); if(c){ TDistant_Attack* da = bTargetBuilding->defensiveFire(c->um); //preplanuj na dalsi strelbu bTargetBuilding->script(this, ktime + BLASTATTACK_REALOAD); // iAttackerLoss--; } } } //====================== //=== ROLE: bojovnik === //====================== else { c = getCombatant((TUnitMember*)so); assert(c); //====================== //=== opustit scenar === //====================== if(c->finished){ leavescript(so); } //===================== //=== ROLE: obrance === //===================== else if( c->defender ){ //============ //=== umri === //============ if(c->slaughtered){ if( RAND(0,1)>BLASTATTACK_FLYAWAY_TRESHOLD ){ c->um->setTransparency(1); c->um->flyAway(); } else c->um->die(); leavescript(so); } //=========================== //=== strelecky protiutok === //=========================== else if( (iAttackerLoss>0 || c->counterattack) && DISTANT(uDefender->guiuiInfo.attackType) && (attackers() > 0) ){ c2 = findRandomCombatant(0); //----------------------- //--- neni koho zabit --- //----------------------- if(!c2){ //TODO: vystrel smerem c->um->script(this, -1); } //------------- //--- zabij --- //------------- else { //---------------- //--- katapult --- //---------------- if( uDefender->guiuiInfo.attackType==atCatapultAttack ) { } //------------------- //--- luk, kouzlo --- //------------------- else { TDistant_Attack* da = c->um->fire(c2->um); iAttackerLoss--; } // c->um->script(this, c->um->iLastAnimationEnd + BLASTATTACK_REALOAD); } //povinny protiutok c->counterattack = 0; } //================= //=== ukonci se === //================= else if(!attackers()){ c->finished = 1; c->um->script(this, -1); } //===================== //=== dalsi kolecko === //===================== else c->um->script(this, ktime+BLASTATTACK_IDLE); } //===================== //=== ROLE: utocnik === //===================== else{ //=================== //=== najdi cestu === //=================== if(!c->attackpos) { P2F route_buff[10]; P2F tangent_buff[10]; int beg = 0; float urad = SizeV2(c->ump.p2fDim.p)/2; P3F ap; P2F dir, pos; c->um->getPosition(&ap); //====================== //=== vylez z budovy === //====================== if( c->inbuilding && c->inbuilding==bAttackerBuilding ){ P2F tb, out_dir; //zviditelni se if( CLOSEDBUILDING(bAttackerBuilding) ) c->um->fadein(); //smer utoku if(bTargetBuilding){ tb = bTargetBuilding->hexWhereIam->aabbCenter.p2f; } else{ tb = uDefender->hexWhereIam->aabbCenter.p2f; } out_dir = ( TVector(tb) - TVector(ap) ).toP2F(); // beg += bAttackerBuilding->generateRouteOutside(&out_dir, route_buff + beg, tangent_buff + beg, 10, urad); c->inbuilding = NULL; } //==================== //=== najdi budovu === //==================== if(bTargetBuilding) { bTargetBuilding->getAttackPosition(&(ap.p2f), &dir, &pos); } //====================== //=== najdi jednotku === //====================== else { findCombatantPosition(c, &ump, &c2); pos = ump.p2fPos; dir = ump.p2fDir; } //pripoj pozici k ceste route_buff[beg] = pos; tangent_buff[beg] = dir; beg++; c->attackpos = 1; c->um->go(beg, route_buff, tangent_buff); c->um->script(this, -1); } //============ //=== umri === //============ else if(c->slaughtered && c->attackpos){ c->um->die(); leavescript(so); } //================================ //=== jsem na miste->vybouchni === //================================ else{ TUnitMember* um = (TUnitMember*)so; TDestruction* des = TDestruction::installDestruction(&(um->aabbCenter), BLASTATTACK_EXPLOSION_DUR, 150, ktime); //------------------------------------------- //--- znic panacky kteri maji byt zniceny --- //------------------------------------------- while(iAttackerKills){ c2 = findRandomCombatant(1); c2->slaughtered = (!INDIVIDUAL(c2->um)) || DEFENDING_INDIVIDUAL_SLAUGHTERED; c2->um->script(this, ktime+(int)RAND(0,BLASTATTACK_REACTION_DEALAY) ); c2->um->setTransparency(1); iAttackerKills--; } //--------------------- //--- znic utocnika --- //--------------------- for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { if( !(*cit).defender ) { (*cit).slaughtered = 1; (*cit).um->script(this, ktime+(int)RAND(0,BLASTATTACK_REACTION_DEALAY) ); } } //-------------------------- //--- poskod/znic budovu --- //-------------------------- if( bTargetBuilding ){ if( bBuildingDestroyed ){ guimap->buildingRemoved_sensor(bTargetBuilding); bTargetBuilding->bc->removeAllActions(); bTargetBuilding->destroyBuilding(); bTargetBuilding->remove(); bTargetBuilding = NULL; bBuildingDestroyed = 0; } else{ while(iBuildingDamaged){ bTargetBuilding->sufferDamage(ktime); iBuildingDamaged--; } //shodit vlajku if(bDefenderKilled){ bTargetBuilding->hangDownFlag(); } } } }//else vybouchni }//else utocnik }//else bojovnik } TBlastAttack::TBlastAttack( TUnit* attacker, TUnit* defender, TBuilding* b, int kills, int loss, bool ak, bool dk, int bdamaged, bool bdestroyed, TIntContainer* ah, TIntContainer* dh) :TCombat(attacker, defender, b, kills, loss, ak, dk, bdamaged, bdestroyed, ah, dh) { TCombatant com; //utocnici for(vunitmember::iterator ait = uAttacker->vMembers.begin(); ait != uAttacker->vMembers.end(); ait++) { initCombatant(&com, *ait, 0); combatants.push_back(com); } //obranci if(uDefender) { for(vunitmember::iterator dit = uDefender->vMembers.begin(); dit != uDefender->vMembers.end(); dit++) { initCombatant(&com, *dit, 1); combatants.push_back(com); } } //pocatecni rozhodnuti bojovniku for(vector::iterator cit = combatants.begin(); cit != combatants.end(); cit++) { this->decision( (TScriptedObject*)(*cit).um ); } //pocatecni rozhodnuti budovy if(bTargetBuilding) decision( (TScriptedObject*)bTargetBuilding ); } //TMarchMove //----------------------------------------------------------------------------- void TMarchMove::decision(TScriptedObject* so){ //============================ //=== dosazeni hexu prvnim === //============================ if(hexReached < ((int)marchPath.size()-2)){ hexReached++; planSegment( &(marchPath[hexReached]), &(marchPath[hexReached+1]) ); } //============================ //=== dosazeni konce cesty === //============================ else{ umleft--; } } int TMarchMove::getStatusMsg(char* buff, int size){ return snprintf(buff, size, "MarchMoveScript: umleft: %d", umleft); } void TMarchMove::moveToFormation(){ //formace P2F p, d; TFormation* formation; formation = unit->getFormation(); formation->getUnitPos(&p, &d); // int ums = (int)unit->vMembers.size(); int used[MAX_UNIT_MEMBERS]; for(int j = 0; j < ums; j++)used[j] = 0; //najdi clena pro kazdou pozici for(int i = 0; i < formation->vumpPositions_c; i++) { //najdi nejblizsiho neobsazenyho panacka float min = FLT_MAX; float dist = 0; int minno = 0, no = 0; vunitmember::iterator nearest_it = unit->vMembers.begin(); for(vunitmember::iterator m_it = unit->vMembers.begin(); m_it != unit->vMembers.end(); m_it++) { dist = DISTV2(formation->vumpPositions[i].p2fPos.p, (*m_it)->aabbCenter.p); if( (dist < min) && !used[no] ){ min = dist; nearest_it = m_it; minno = no; } no++; } used[minno] = 1; (*nearest_it)->go(&(formation->vumpPositions[i].p2fPos) ,&(d)); } } void TMarchMove::getInside(TBuilding* b, P2F* in_dir){ P2F control_points[10]; P2F tangents[10]; P2F pos, dim; int route_len; int um_counter = 0; float rad; TFormation* formation = unit->getFormation(); //vycisti pozice if( OPENBUILDING(b) ) ((TOpenStructure*)b)->clearPositions(); //nastav pochod kazdeho clena for(vunitmember::iterator m_it = unit->vMembers.begin(); m_it != unit->vMembers.end(); m_it++) { // (*m_it)->getModelDim(&dim); rad = SizeV2(dim.p)/2; //vygeneruj cestu route_len = b->generateRouteInside(in_dir, control_points, tangents, 10, rad); //pokud "otevrena" budova vygeneruj polohu uvnitr if( OPENBUILDING(b) ){ ((TOpenStructure*)b)->findPosition(&dim, &pos); //nastaveni formace formation->vumpPositions[um_counter].p2fDir = tangents[route_len-1]; formation->vumpPositions[um_counter].p2fDim = dim; formation->vumpPositions[um_counter].p2fPos = pos; //nastaveni posledniho bodu cesty control_points[route_len] = pos; tangents[route_len] = tangents[route_len-1]; route_len++; //jdi (*m_it)->go(route_len, control_points, tangents); } else{ (*m_it)->go(route_len, control_points, tangents); (*m_it)->fadeout(); } // um_counter++; } } void TMarchMove::getOutside(TBuilding* b, P2F* out_dir){ P2F control_points[10]; P2F tangents[10]; P2F dim; int route_len; float rad; // for(vunitmember::iterator m_it = unit->vMembers.begin(); m_it != unit->vMembers.end(); m_it++) { // (*m_it)->getModelDim(&dim); rad = SizeV2(dim.p)/2; //vygeneruj kontrolni body+tecny cesty route_len = b->generateRouteOutside(out_dir, control_points, tangents, 10, rad); //umisti jednotku k vychodu if( CLOSEDBUILDING(b) ){ P3F pos = {0,0,0}; P3F dir = {0,0,0}; P3F up = {0,0,1}; pos.p2f = control_points[0]; dir.p2f = tangents[0]; (*m_it)->place(&pos, &dir, &up); //zviditelni jednotku (*m_it)->fadein(); } //vytvor drahu (*m_it)->go(route_len, control_points, tangents); } } void TMarchMove::planSegment(TStep* curr_step, TStep* next_step){ THex* curr = guimap->hexy[curr_step->hex_id]; THex* next = guimap->hexy[next_step->hex_id]; P3F hexcenter1, hexcenter2; P2F dir; TFormation* formation = unit->getFormation(); TBuilding* building; curr->getHexCenter(&hexcenter1); next->getHexCenter(&hexcenter2); dir = ( TVector(hexcenter2) - TVector(hexcenter1) ).toP2F(); #ifndef STEERING //nastav prekazky TTerrainEntity* terr = (TTerrainEntity*)next->getProxy(ptTerrain); formation->avoidTerrainObstacles(terr); #endif formation->setStandardFormation( &(hexcenter2.p2f), &dir ); //vyjdi z budovy building = (TBuilding*)curr->getProxy(ptBuilding); if(building){ getOutside(building, &dir); building->hangDownFlag(); } //vejdi do budovy building = (TBuilding*)next->getProxy(ptBuilding); if(building){ getInside(building, &dir); building->hangUpFlag(); } else{ moveToFormation(); } unit->moveToHex(next->getIndex()); // for(vunitmember::iterator m_it = unit->vMembers.begin(); m_it != unit->vMembers.end(); m_it++) (*m_it)->script(this, -1); //posli zprava pro odkryti mapy if(guimap) guimap->unitMoved_sensor( &(marchPath[hexReached+1]) ); } TMarchMove::TMarchMove(TUnit* u, TPath *path) :TSceneScript(u->map) { //nastaveni dat unit = u; umleft = unit->getUnitMemberCount(); marchPath = *path; hexReached = 0; //naplanuj prvni krok planSegment( &(marchPath[0]), &(marchPath[1]) ); } //TBuildBuilding //----------------------------------------------------------------------------- void TBuildBuilding::decision(TScriptedObject* so){ //==================== //=== ROLE: budova === //==================== if( so == (TScriptedObject*)bBuilding ) { bBuilding->transparency(0); } //====================== //=== ROLE: stavitel === //====================== else{ TUnitMember* um = (TUnitMember*)so; if(builder_at_position[so] == 0) { //naplanuj pochod na stavebni pozici goToBuilderPosition( um ); builder_at_position[so] = 1; um->script(this); } else { //zviditelneni staveniste bBuilding->transparency(1); //premisti stavitele uBuilder->moveToHex(bBuilding->hexWhereIam->getIndex()); } } } void TBuildBuilding::goToBuilderPosition(TUnitMember* umb){ P2F p, bp, bd; P2F control_points[20]; P2F tangents[20]; int route_len = 0; float urad = 0; //pozice a velikost panacka p = umb->aabbCenter.p2f; urad = SizeV2(umb->aabbDim.p); //odpovidajici pozice stavitele bBuilding->findNearestBuilderPosition(&p, &bp, &bd); //vylez z budovy if(bSourceBuilding) { umb->fadein(); P2F out_dir = ( TVector(bp) - TVector(p) ).toP2F(); route_len += bSourceBuilding->generateRouteOutside(&out_dir, control_points + route_len, tangents + route_len, 20, urad); //nastav na vystupni pozici P3F pos = {0,0,0}; P3F dir = {0,0,0}; P3F up = {0,0,1}; // pos.p2f = control_points[0]; dir.p2f = tangents[0]; umb->place(&pos, &dir, &up); } //pridej pozici control_points[route_len] = bp; tangents[route_len] = bd; route_len++; // umb->go(route_len, control_points, tangents); } TBuildBuilding::TBuildBuilding(TUnit* builder, TBuilding* building, THex* sitehex) :TSceneScript(builder->map) { uBuilder = builder; bBuilding = building; bSourceBuilding = (TBuilding*)builder->hexWhereIam->getProxy(ptBuilding); hSite = sitehex; //velejzam z budovy kteoru teprve stavim! if( bSourceBuilding == bBuilding )bSourceBuilding = NULL; //rozhodnuti stavitele for(vunitmember::iterator m_it = uBuilder->vMembers.begin(); m_it != uBuilder->vMembers.end(); m_it++) { builder_at_position.insert( std::make_pair((TScriptedObject*)*m_it, 0) ); decision((TScriptedObject*)*m_it); } //rozhodnuti budovy decision((TScriptedObject*)bBuilding); } int TBuildBuilding::getStatusMsg(char* buff, int size){ return snprintf(buff, size, "BuildingScript"); } //TReleaseUnit //----------------------------------------------------------------------------- TReleaseUnit::TReleaseUnit(TUnit* u, TIntContainer h) :TSceneScript(u->map) { int ktime = KTime(); for(vunitmember::iterator m_it = u->vMembers.begin(); m_it != u->vMembers.end(); m_it = u->vMembers.begin()) { TUnitMember* um = (*m_it); um->die(); } //odstraneni z budovy gui::TBuilding* b = (gui::TBuilding*)u->hexWhereIam->getProxy(ptBuilding); if(b){ b->hangDownFlag(); } //viditelnost guimap->visibilityAltered_sensor(NULL, &h, u->guiuiInfo.player); //odostranit jednotku guimap->unitRemoved_sensor(u); gui::TUnit::uninstallUnit(guimap, u->guiuiInfo.livingunit, false); //log SCLOG("TReleaseUnit::decision - deleting release unit script instance\n"); } void TReleaseUnit::decision(TScriptedObject* so){ } int TReleaseUnit::getStatusMsg(char* buff, int size){ return snprintf(buff,size,"release unit script\n"); } //TDemolishBuilding //----------------------------------------------------------------------------- #define DEMOLISHBUILDING_DIE_DELAY 8000 TDemolishBuilding::TDemolishBuilding(TBuilding* b, TIntContainer h) :TSceneScript(b->map) { //exploze b->destroyBuilding(); //odstran b->remove(); //uprav vyhled guimap->visibilityAltered_sensor(NULL, &h, b->guibiInfo.player); //odstran budovu guimap->buildingRemoved_sensor(b); //zrus jednotku uvnitr gui::TUnit* u = (gui::TUnit*)b->hexWhereIam->getProxy(ptDynamic); if(u){ b->hangDownFlag(); // for(vunitmember::iterator m_it = u->vMembers.begin(); m_it != u->vMembers.end(); m_it = u->vMembers.begin()) { TUnitMember* um = (*m_it); um->setTransparency(1); um->flyAway(); } //odstran jednotku guimap->unitRemoved_sensor(u); gui::TUnit::uninstallUnit(guimap, u->guiuiInfo.livingunit, false); } // SCLOG("TDemolishBuilding::decision - deleting demolish building script instance\n"); } void TDemolishBuilding::decision(TScriptedObject* so) { } int TDemolishBuilding::getStatusMsg(char* buff, int size) { return snprintf(buff,size,"building demolition script\n"); } //TRepairBuilding //----------------------------------------------------------------------------- TRepairBuilding::TRepairBuilding(TUnit* builder, TBuilding* building, TIntContainer s, TIntContainer h) :TSceneScript(builder->map) { uBuilder = builder; bBuilding = building; bSourceBuilding = (TBuilding*)builder->hexWhereIam->getProxy(ptBuilding); //rozhodnuti stavitele for(vunitmember::iterator m_it = uBuilder->vMembers.begin(); m_it != uBuilder->vMembers.end(); m_it++) { builder_at_position.insert( std::make_pair((TScriptedObject*)*m_it, 0) ); decision((TScriptedObject*)*m_it); } //rozhodnuti budovy decision((TScriptedObject*)bBuilding); //premisti int hex = bBuilding->hexWhereIam->getIndex(); uBuilder->moveToHex(hex); //posli zprava pro odkryti mapy if(guimap) guimap->visibilityAltered_sensor(&s, &h, uBuilder->guiuiInfo.player); } void TRepairBuilding::decision(TScriptedObject* so) { //==================== //=== ROLE: budova === //==================== if( so == ((TScriptedObject*)bBuilding) ) { } //====================== //=== ROLE: stavitel === //====================== else { //---------------------- //--- neni na pozici --- //---------------------- if( builder_at_position[so] == 0 ) { // P2F control_points[10]; P2F tangents[10]; int route_len = 0; TUnitMember* um = (TUnitMember*)so; float rad = SizeV2(um->aabbDim.p)/2; P2F tb, in_dir; // bBuilding->getPosition(&tb); in_dir = ( TVector(tb) - TVector(um->aabbCenter.p2f) ).toP2F(); //----------------------- //--- otevrena budova --- //----------------------- if( OPENBUILDING(bBuilding) ) { // nejsem v budove, kterou mam opravit if(bSourceBuilding != bBuilding) { //najdi cestu do budovy route_len = bBuilding->generateRouteInside(&in_dir, control_points, tangents, 10, rad); } else { //nic } //stejne bBuilding->findNearestBuilderPosition( &(um->aabbCenter.p2f), control_points+route_len, tangents+route_len); route_len++; //jdi um->go(route_len, control_points, tangents); } //---------------- //--- uzavrena --- //---------------- else { // nejsem v budove, kterou mam opravit if(bSourceBuilding != bBuilding){ //najdi cestu do budovy route_len = bBuilding->generateRouteInside(&in_dir, control_points, tangents, 10, rad); //jdi um->go(route_len, control_points, tangents); //zmiz um->fadeout(); } else { //nic } } um->script(this); builder_at_position[so] = 1; } //----------------- //--- ukonci se --- //----------------- else { } } } int TRepairBuilding::getStatusMsg(char* buff, int size) { return snprintf(buff,size,"Repair building script\n"); } //TUnitDeserted //----------------------------------------------------------------------------- TUnitDeserted::TUnitDeserted(TUnit* u, TIntContainer h) :TSceneScript(u->map) { for(vunitmember::iterator m_it = u->vMembers.begin(); m_it != u->vMembers.end(); m_it++){ // P2F dir; int ktime = KTime(); SETV2(dir.p, RAND(-200,200), RAND(-200,200)); P2F pos=(*m_it)->aabbCenter.p2f; AddV2(pos.p, dir.p); // (*m_it)->go(&pos, &dir, ktime); (*m_it)->umc->fadeout(5000, ktime); (*m_it)->umc->disappear(ktime + 6000); } //odostranit jednotku guimap->unitRemoved_sensor(u); gui::TUnit::uninstallUnit(guimap, u->guiuiInfo.livingunit, false); } void TUnitDeserted::decision(TScriptedObject* so){ } int TUnitDeserted::getStatusMsg(char* buff, int size) { return snprintf(buff,size,"Unit Deserted script\n"); } //TUnitMemberDied //----------------------------------------------------------------------------- TUnitMemberDied::TUnitMemberDied(TUnit* u, int count) :TSceneScript(u->map) { //=================== //=== Jednotlivec === //=================== if(u->guiuiInfo.formation == ftIndividualFormation){ //jenom krev (*u->vMembers.begin())->bleed(KTime()); } //======================= //=== Skupina vojacku === //======================= else { vunitmember::iterator m_it; for(int i = 0; i < count; i++){ //zabij panacka m_it = u->vMembers.begin(); (*m_it)->die(); } } //skript ukoncen } void TUnitMemberDied::decision(TScriptedObject* so){ } int TUnitMemberDied::getStatusMsg(char* buff, int size) { return snprintf(buff,size,"Unit Member Died script\n"); } }//namespace /*****************************************************************************/