//:://///////////////////////////////////////////// //:: Name q2_inc_battle //:: Copyright (c) 2001 Bioware Corp. //::////////////////////////////////////////////// /* Battle for Lith My'athar Include file */ //::////////////////////////////////////////////// //:: Created By: Keith Warner //:: Created On: August 19/03 //::////////////////////////////////////////////// #include "nw_i0_generic" #include "nw_i0_plot" //CONSTANTS ****************************** const int UNIT_MOVE_TO_TARGET = 5100; const int LEADER_ORDER_FOLLOW_LEADER = 5101; const int UNIT_ORDER_MAKE_ME_LEADER = 5102; const int DROW_UNIT_MOVE_TO_INITIAL_TARGET = 5103; const int UNIT_ORDER_PATROL_CURRENT_LOCATION = 5104; const int LEADER_ORDER_CHECK_FOR_ENEMIES = 5105; const int HOTSPOT_CHECK = 5106; const int DROW_ORDER_DEFEND_HOTSPOT = 5107; const int BATTLE1_DROW_VICTORY = 5108; const int HEALER_ORDER_HEAL_REBELS = 5109; const int UNIT_ORDER_PATROL_TOWER = 5110; const int BATTLEMASTER_FIND_NEW_GATE_ATTACKER = 5111; const int BATTLEMASTER_SIGNAL_RETREAT = 5112; const int BATTLEMASTER_SIGNAL_ALL_ADVANCE = 5113; const int BATTLEMASTER_RESPAWN_WAVE = 5114; const int BATTLE2_PLAYER_VICTORY = 5115; const int BATTLE2_PLAYER_DEFEAT = 5116; const int BATTLEMASTER_SIGNAL_WAVE2_RETREAT = 5117; const int BATTLE2_PLAYER_WAVE2_VICTORY = 5118; const int BATTLE2_WAVE2_REBEL_ADVANCE = 5119; const int BATTLEMASTER_RESPAWN_WAVE_WAVE2 = 5120; const int UNIT_ORDER_STAND_POST = 5121; const int BATTLEMASTER_SIGNAL_WAVE3_RETREAT = 5122; const int BATTLE2_PLAYER_WAVE3_VICTORY = 5123; const int BATTLE2_WAVE3_REBEL_ADVANCE = 5124; const int BATTLEMASTER_RESPAWN_WAVE_WAVE3 = 5125; const int BATTLEMASTER_SIGNAL_WAVE4_RETREAT = 5126; const int BATTLE2_PLAYER_WAVE4_VICTORY = 5127; const int BATTLE2_WAVE4_REBEL_ADVANCE = 5128; const int BATTLE1_RETREAT_NUMBER = 6; //FUNCTION DEFINITIONS ************************************** //A leader unit calls this function to order all troops in his formation to //move to his target object void BattleOrder_MoveTroopsToTarget(object oTarget); //Specify a fraction if you want a fraction of a second delay //Max Seconds divided by nDivisor float GetRandomDelay2(int nMaxSeconds, float fFraction = 1.0); //A formation leader has died so elect a new one. void Formation_ElectNewLeader(int nFormNumber); //Spawn in Rebels //Create a formation of 5 of the specified creatures and move them to oTarget //Make one of the creatures a leader. void CreateRebelFormation(int nFormNumber, string szResRef, location lSpawn, object oTarget); //Create 1 rebel cleric and move them to oTarget void CreateRebelCleric(string szResRef, location lSpawn, object oTarget); //The leader of a formation has seen the enemy so formation will attack void BattleOrder_FormationAttack(object oEnemy); //A leader unit calls this function to order all troops in his formation to //attack this target location void BattleOrder_TroopsAttackTarget(object oTarget); //Drow Catapult picking a target trigger in which to look for a target object DrowCatapult_PickTargetArea(); //DrowCatapult picking a target unit in a target area; object DrowCatapult_PickTargetUnit(object oTargetLocation); //Drow Catapult has no specific target - so get a random location near the target trigger location DrowCatapult_PickRandomLocation(object oTargetLocation); //Create a drow catapult team at the given location void CreateDrowCatapult(location lCatapult1); //Check to see if the Drow Catapult Fire team is alive int DrowCatapult_FireTeamAlive(object oBallista); //Check to see if the Rebel Catapult Fire team is alive int RebelCatapult_FireTeamAlive(object oBallista); //Spawn a group of attackers at a specific location void SpawnGroupAt(int nFormation, string szResRef, object oTarget, location lSpawn); //All group members should know of each other group member. void SetFormation(int nFormation, string szResRef); //FUNCTIONS **************************** //A leader unit calls this function to order all troops in his formation to //move to his target object void BattleOrder_MoveTroopsToTarget(object oTarget) { object oPC = GetFirstPC(); int nFormNumber = GetLocalInt(OBJECT_SELF, "nFormation"); //SendMessageToPC(oPC, "Formation Number :" + IntToString(nFormNumber)); string szTag = GetResRef(OBJECT_SELF); string szUnit; //SendMessageToPC(oPC, "szTag :" + szTag); float fDelay; int nCount; object oUnit; for (nCount = 1; nCount < 6; nCount++) { szUnit = szTag + IntToString(nFormNumber) + IntToString(nCount); //SendMessageToPC(oPC, "Looking for Tag :" + szUnit); oUnit = GetObjectByTag(szUnit); if (GetIsObjectValid(oUnit) == TRUE) { //SendMessageToPC(oPC, "Unit Valid"); SetLocalObject(oUnit, "oMoveTarget", oTarget); //Allow Patrolling to commence SetLocalInt(oUnit, "nFirstOrders", 1); AssignCommand(oUnit, ClearAllActions()); fDelay = GetRandomDelay2(2, 0.9); DelayCommand(fDelay, AssignCommand(oUnit, ActionPlayAnimation(ANIMATION_FIREFORGET_SALUTE))); if (Random(3) == 2) DelayCommand(fDelay + 0.1, AssignCommand(oUnit, PlaySpeakSoundByStrRef(85762)));//"Yes Sir!" DelayCommand(2.0, AssignCommand(oUnit, ActionForceMoveToObject(oTarget, TRUE, 1.0, 12.0))); DelayCommand(5.0, SignalEvent(oUnit, EventUserDefined(UNIT_MOVE_TO_TARGET))); } //else //SendMessageToPC(oPC, "Unit INValid"); } } //Specify a divisor if you want a fraction of a second delay //Max Seconds divided by nDivisor float GetRandomDelay2(int nMaxSeconds, float fFraction = 1.0) { float fRandom = IntToFloat(Random(nMaxSeconds + 1)) * fFraction; return fRandom; } //A formation leader has died so elect a new one. void Formation_ElectNewLeader(int nFormNumber) { string szDeadUnitTag = GetTag(OBJECT_SELF); string szTag = GetStringLeft(GetTag(OBJECT_SELF), 11); string szUnit; effect eVis = EffectVisualEffect(VFX_DUR_FLAG_GOLD); int nCount; int bFound = FALSE; object oUnit; //Cycle through the units until one is found alive -make him the new leader. for (nCount = 1; nCount < 6 && bFound == FALSE; nCount++) { szUnit = szTag + IntToString(nFormNumber) + IntToString(nCount); oUnit = GetObjectByTag(szUnit); if (GetIsObjectValid(oUnit) == TRUE) { if (GetTag(oUnit) != szDeadUnitTag) { SetLocalInt(oUnit, "nLeader", 1); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVis, oUnit); SignalEvent(oUnit, EventUserDefined(UNIT_ORDER_MAKE_ME_LEADER)); bFound = TRUE; } } } } //Spawn in Rebels //Create a formation of 5 of the specified creatures and move them to oTarget //Make one of the creatures a leader. void CreateRebelFormation(int nFormNumber, string szResRef, location lSpawn, object oTarget) { int nCount; for (nCount = 1; nCount < 6; nCount++) { object oUnit = CreateObject(OBJECT_TYPE_CREATURE, szResRef, lSpawn, FALSE, szResRef + IntToString(nFormNumber) + IntToString(nCount)); if (nCount == 1) { SetLocalInt(oUnit, "nLeader", 1); effect eVis = EffectVisualEffect(VFX_DUR_FLAG_GOLD); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVis, oUnit); object oHelm = CreateItemOnObject("q2arebleadhelm", oUnit); SetDroppableFlag(oHelm, FALSE); AssignCommand(oUnit, ActionEquipItem(oHelm, INVENTORY_SLOT_HEAD)); } SetLocalInt(oUnit, "nFormation", nFormNumber); SetLocalObject(oUnit, "oMoveTarget", oTarget); DelayCommand(0.5, AssignCommand(oUnit, ActionForceMoveToObject(oTarget, TRUE, 1.0, 10.0))); DelayCommand(6.0, SignalEvent(oUnit, EventUserDefined(UNIT_MOVE_TO_TARGET))); } } //Create 1 rebel cleric and move them to oTarget void CreateRebelCleric(string szResRef, location lSpawn, object oTarget) { object oUnit = CreateObject(OBJECT_TYPE_CREATURE, szResRef, lSpawn); SetLocalObject(oUnit, "oMoveTarget", oTarget); AssignCommand(oUnit, ActionForceMoveToObject(oTarget, TRUE)); SignalEvent(oUnit, EventUserDefined(UNIT_MOVE_TO_TARGET)); } //The leader of a formation has seen the enemy so formation will attack void BattleOrder_FormationAttack(object oEnemy) { int nCount; string szUnit; string szTag = GetStringLeft(GetTag(OBJECT_SELF), 11); object oUnit; int nFormNumber = GetLocalInt(OBJECT_SELF, "nFormation"); //Cycle through the units until one is found alive -make him the new leader. for (nCount = 1; nCount < 6; nCount++) { szUnit = szTag + IntToString(nFormNumber) + IntToString(nCount); oUnit = GetObjectByTag(szUnit); if (GetIsObjectValid(oUnit) == TRUE) { SetLocalInt(oUnit, "nEngageEnemy", 1); AssignCommand(oUnit, DetermineCombatRound()); } } } //A leader unit calls this function to order all troops in his formation to //attack this target location void BattleOrder_TroopsAttackTarget(object oTarget) { object oPC = GetFirstPC(); //SendMessageToPC(oPC, "Troops Attacking Target"); int nFormNumber = GetLocalInt(OBJECT_SELF, "nFormation"); string szTag = GetStringLeft(GetTag(OBJECT_SELF), 16); //x2_q2drowarcher2 string szUnit; //x2_q2drowwarrio2 float fDelay; int nCount; object oUnit; for (nCount = 1; nCount < 6; nCount++) { szUnit = szTag + IntToString(nFormNumber) + IntToString(nCount); oUnit = GetObjectByTag(szUnit); if (GetIsObjectValid(oUnit) == TRUE) { SetLocalObject(oUnit, "oMoveTarget", oTarget); //SetLocalInt(oUnit, "nTargetPicked", 1); if (GetIsInCombat(oUnit) == FALSE) { AssignCommand(oUnit, ActionMoveToObject(oTarget, TRUE)); } DelayCommand(5.0, SignalEvent(oUnit, EventUserDefined(UNIT_MOVE_TO_TARGET))); } //else //SendMessageToPC(oPC, "Unit INValid"); } } //Drow Catapult picking a target trigger in which to look for a target object DrowCatapult_PickTargetArea() { int nRandom = Random(6) + 1; object oTarget = GetObjectByTag("bat1_cattarget" + IntToString(nRandom)); return oTarget; } //DrowCatapult picking a target unit in a target area; object DrowCatapult_PickTargetUnit(object oTargetLocation) { object oFireTarget = OBJECT_INVALID; int bFound = FALSE; object oTarget = GetFirstInPersistentObject(oTargetLocation); while (oTarget != OBJECT_INVALID && bFound == FALSE) { //Will pick either a rebel drow or the PC if (GetStringLeft(GetTag(oTarget), 10) == "q2abat1reb" || GetIsPC(oTarget) == TRUE) { oFireTarget = oTarget; bFound = TRUE; } oTarget = GetNextInPersistentObject(oTargetLocation); } return oFireTarget; } //Drow Catapult has no specific target - so get a random location near the target trigger location DrowCatapult_PickRandomLocation(object oTargetLocation) { object oArea = GetArea(oTargetLocation); vector vStart = GetPosition(oTargetLocation); float fAngle = IntToFloat(Random(360)); float fDistance = IntToFloat(Random(10)+1); float fNewx = cos(fAngle)*fDistance + vStart.x; float fNewy = sin(fAngle)*fDistance + vStart.y; vector vNew = Vector(fNewx, fNewy, vStart.z); location lTarget = Location(oArea, vNew, 0.0); return lTarget; } //Check to see if the Drow Catapult Fire team is alive int DrowCatapult_FireTeamAlive(object oBallista) { object oDrow = GetNearestObjectByTag("q2a_drowcatteam", oBallista); if (GetIsObjectValid(oDrow) == TRUE) { if (GetDistanceBetween(oBallista, oDrow) < 5.0) return TRUE; } return FALSE; } //Check to see if the Rebel Catapult Fire team is alive int RebelCatapult_FireTeamAlive(object oBallista) { object oDrow = GetNearestObjectByTag("q2a_rebcatteam", oBallista); if (GetIsObjectValid(oDrow) == TRUE) { if (GetDistanceBetween(oBallista, oDrow) < 5.0) return TRUE; } return FALSE; } //Create a drow catapult team at the given location void CreateDrowCatapult(location lCatapult) { object oCat = CreateObject(OBJECT_TYPE_PLACEABLE, "q2a_bat1drowcat", lCatapult); CreateObject(OBJECT_TYPE_CREATURE, "q2a_drowcatteam", lCatapult); CreateObject(OBJECT_TYPE_CREATURE, "q2a_drowcatteam", lCatapult); } //Spawn a group of attackers at a specific spot. void SpawnGroupAt(int nFormation, string szResRef, object oTarget, location lSpawn) { //object oPC = GetFirstPC(); if (GetIsObjectValid(oTarget) == FALSE) oTarget = GetObjectByTag("q2ainnergate"); object oBattleMaster = GetObjectByTag("bat1_battlemaster"); //Track how many Drow formations have been created (for retreat purposes) SetLocalInt(oBattleMaster, "nBattle1DrowFormCount", GetLocalInt(oBattleMaster, "nBattle1DrowFormCount") + 1); //location lSpawn = GetLocation(GetWaypointByTag("wp_bat1_drowspawn" + IntToString(Random(3) + 1))); int nCount; object oCreature; object oGate = GetObjectByTag("q2acitygate"); int nAdvance = TRUE; if (GetIsObjectValid(oGate) == TRUE) nAdvance = FALSE; for (nCount = 1; nCount < 6; nCount++) { oCreature = CreateObject(OBJECT_TYPE_CREATURE, szResRef, lSpawn, FALSE, szResRef + IntToString(nFormation) + IntToString(nCount)); if (nCount == 1) { //Store a pointer to the leader of each group on the battlemaster SetLocalObject(oBattleMaster, "oFormationLeader" + IntToString(nFormation), oCreature); SetLocalInt(oCreature, "nLeader", 1); //ADVANCE DelayCommand(2.0, SignalEvent(oCreature, EventUserDefined(5000))); } SetLocalInt(oCreature, "nFormation", nFormation); SetLocalObject(oCreature, "oTarget", oTarget); //KLUDGE ATTEMPT if (nAdvance == TRUE) DelayCommand(IntToFloat(nCount), AssignCommand(oCreature, ActionMoveToObject(oTarget, TRUE))); //SendMessageToPC(oPC, GetTag(oCreature)); } SetFormation(nFormation, szResRef); } //All group members should know of each other group member. void SetFormation(int nFormation, string szResRef) { // all members of the formation will have pointers to all other members stored locally object oPC = GetFirstPC(); int nCount = 1; int nCount2 = 1; object oFormMember; object oPointer; for (nCount = 1; nCount < 6; nCount++) { oFormMember = GetObjectByTag(szResRef + IntToString(nFormation) + IntToString(nCount)); //SendMessageToPC(oPC, "oFormMember" + IntToString(nCount) + " gets:"); for (nCount2 = 1; nCount2 < 6; nCount2++) { oPointer = GetObjectByTag(szResRef + IntToString(nFormation) + IntToString(nCount2)); SetLocalObject(oFormMember, "oFormMember" + IntToString(nCount2), oPointer); //SendMessageToPC(oPC, GetTag(oPointer)); } } }