mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-07-29 23:15:55 -04:00
1431 lines
40 KiB
Plaintext
1431 lines
40 KiB
Plaintext
//////////////////////////////////////////////
|
|
// FS Combat Quest Phase 3 -- Counterstrike //
|
|
//////////////////////////////////////////////
|
|
|
|
// INCLUDES
|
|
include library.create;
|
|
include library.fs_dyn_village;
|
|
include library.trace;
|
|
include library.utils;
|
|
include library.locations;
|
|
|
|
// STRING constants
|
|
const string MOUSE_DROID_NAME_ID = "name_mdroid_";
|
|
const string SHIELD_TR_VOLUME = "fs_camp.tr_volume";
|
|
const string CAMP_DOOR_TEMPLATE = "object/installation/battlefield/destructible/bfield_base_gate_impl.iff";
|
|
const string CAMP_ANTENNA_TEMPLATE = "object/installation/battlefield/destructible/antenna_tatt_style_1.iff";
|
|
const string CAMP_TURRET_TEMPLATE = "object/installation/turret/generic_turret_block_sm.iff";
|
|
const string CAMP_TENT_TEMPLATE = "object/static/structure/corellia/corl_tent_hut_s01.iff";
|
|
|
|
// NUMERIC constants
|
|
const float SHIELD_RADIUS = 50.0f;
|
|
const float SHIELD_REMOTE_RANGE = 75.0f; // 100 m
|
|
const int MAX_DROIDS_FOR_CAMP = 5;
|
|
const float MIN_DROID_DISTANCE = 75.0f;
|
|
const float MAX_DROID_DISTANCE = 100.0f;
|
|
const float CAMP_SHIELD_REBOOT_TIME = 7200.0f; // 2.0 hours after being powered down, the shield goes back up (camp resets)
|
|
const int CAMP_BOSS_DEATH_TIME = 3600; // 1 hour after being spawned
|
|
const int CAMP_REINFORCEMENT_MIN = 90; // every 1.5 minutes
|
|
const int CAMP_REINFORCEMENT_MAX = 180; // every 3 minutes minutes
|
|
const int CAMP_LOOT_SPAWN_INTERVAL = 700;
|
|
const int NUM_LOOT_SPAWNS_PER_CAMP = 2;
|
|
const float MIN_LOOT_SPAWN_DISTANCE = 200f;
|
|
const float MAX_LOOT_SPAWN_DISTANCE = 300f;
|
|
|
|
|
|
// DATATABLE constants
|
|
const string DT_TABLE_NAME = "datatables/fs_quests/fs_counterstrike.iff";
|
|
const string DT_TABLE_POI_NAME = "datatables/theater/fs_quest_combat3/fs_quest_combat3.iff";
|
|
const string DT_COL_CAMP_NUM = "camp_number";
|
|
const string DT_COL_CAMP_NAME = "camp_name";
|
|
const string DT_COL_LOC_X = "loc_x";
|
|
const string DT_COL_LOC_Y = "loc_y";
|
|
const string DT_COL_LOC_Z = "loc_z";
|
|
const string DT_COL_CAMP_RADIUS = "camp_radius";
|
|
|
|
// OBJVAR constants
|
|
const string OBJVAR_CAMP_NAME = "fs_cs.camp.name";
|
|
const string OBJVAR_MY_CAMP_ID = "fs_cs.camp.id";
|
|
const string OBJVAR_CREATED_CAMP_IDS = "fs_cs.camps.created.ids";
|
|
const string OBJVAR_CREATED_CAMP_LOCS = "fs_cs.camps.created.locs";
|
|
const string OBJVAR_PHASE_CAMP_NAMES = "fs_cs.camps.hints.names";
|
|
const string OBJVAR_PHASE_CAMP_LOC_HINTS = "fs_cs.camps.hints.locs";
|
|
|
|
const string OBJVAR_CAMP_DOOR1 = "fs_cs.camp.door1";
|
|
const string OBJVAR_CAMP_DOOR1_LOC = "fs_cs.camp.door1Loc";
|
|
const string OBJVAR_CAMP_DOOR1_YAW = "fs_cs.camp.door1Yaw";
|
|
|
|
const string OBJVAR_CAMP_DOOR2 = "fs_cs.camp.door2";
|
|
const string OBJVAR_CAMP_DOOR2_LOC = "fs_cs.camp.door2Loc";
|
|
const string OBJVAR_CAMP_DOOR2_YAW = "fs_cs.camp.door2Yaw";
|
|
|
|
const string OBJVAR_CAMP_TURRET1 = "fs_cs.camp.turret1";
|
|
const string OBJVAR_CAMP_TURRET1_LOC = "fs_cs.camp.turret1Loc";
|
|
const string OBJVAR_CAMP_TURRET1_YAW = "fs_cs.camp.turret1Yaw";
|
|
|
|
const string OBJVAR_CAMP_TURRET2 = "fs_cs.camp.turret2";
|
|
const string OBJVAR_CAMP_TURRET2_LOC = "fs_cs.camp.turret2Loc";
|
|
const string OBJVAR_CAMP_TURRET2_YAW = "fs_cs.camp.turret2Yaw";
|
|
|
|
const string OBJVAR_CAMP_TURRET3 = "fs_cs.camp.turret3";
|
|
const string OBJVAR_CAMP_TURRET3_LOC = "fs_cs.camp.turret3Loc";
|
|
const string OBJVAR_CAMP_TURRET3_YAW = "fs_cs.camp.turret3Yaw";
|
|
|
|
const string OBJVAR_CAMP_TENT_LOC = "fs_cs.camp.tentLoc";
|
|
|
|
const string OBJVAR_CAMP_COMMANDER = "fs_cs.camp.commander";
|
|
const string OBJVAR_CAMP_COMMANDER_TAKER = "fs_cs.camp.commanderTakers";
|
|
const string OBJVAR_CAMP_SHIELD_KILLER = "fs_cs.camp.shieldKiller"; // person who powered down the shield
|
|
const string OBJVAR_CAMP_ANTENNA = "fs_cs.camp.antenna";
|
|
const string OBJVAR_CAMP_ANTENNA_LOC = "fs_cs.camp.antennaLoc";
|
|
const string OBJVAR_CAMP_OBJS = "fs_cs.camp.allObjs";
|
|
const string OBJVAR_CAMP_DROIDS = "fs_cs.camp.droids";
|
|
const string OBJVAR_IS_REMOTE_RECEIVER = "fs_cs.camp.isReceiver"; // this is the object that counts as the remote receiver
|
|
const string OBJVAR_STOP_DEFENSE_SPAWN = "fs_cs.camp.stopDefenses";
|
|
const string OBJVAR_CAMP_GUARDS_KILLED = "fs_cs.campGuardKilled"; // integer of how many camp guards we were responsible for doing most damage to
|
|
const string OBJVAR_BORN_ON = "fs_cs.creationDate";
|
|
|
|
|
|
// NUMERIC constants
|
|
const int MAX_NUM_CAMPS_PER_CYCLE = 20; // maximum number of camps to generate per phase
|
|
|
|
void doCampLootSpawn(obj_id camp)
|
|
{
|
|
location here = getLocation(camp);
|
|
location where = utils.getRandomAwayLocation(here, MIN_LOOT_SPAWN_DISTANCE, MAX_LOOT_SPAWN_DISTANCE);
|
|
obj_id spawner = null;
|
|
long seed = 0;
|
|
|
|
for(int i = 0; i < NUM_LOOT_SPAWNS_PER_CAMP; i++)
|
|
{
|
|
spawner = quests.createSpawner("fs_counterstrike_loot", where, fs_dyn_village.CITY_BAD_GUY_SPAWN_TABLE, camp);
|
|
|
|
if(isIdValid(spawner))
|
|
{
|
|
setObjVar(camp, "fs_cs.lastLootSpawnCreated", where);
|
|
seed = spawner.getValue();
|
|
while(seed > Integer.MAX_VALUE)
|
|
{
|
|
seed /= 2;
|
|
}
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Created camp loot spawner " + spawner + " at " + where.toString());
|
|
}
|
|
reseed((int)seed);
|
|
}
|
|
|
|
messageTo(camp, "msgDoLootSpawn", null, (float)CAMP_LOOT_SPAWN_INTERVAL, false);
|
|
}
|
|
|
|
void resetPlayer(obj_id player)
|
|
{
|
|
string[] possibleSteps = new string[]
|
|
{
|
|
"fs_cs_intro",
|
|
"fs_cs_kill5_guards",
|
|
"fs_cs_ensure_capture",
|
|
"fs_cs_last_chance",
|
|
"fs_cs_escort_commander_pri",
|
|
"fs_cs_escort_commander_sec",
|
|
"fs_cs_quest_done",
|
|
"fs_cs_quest_failed_escort"
|
|
};
|
|
|
|
obj_id questGiver = null;
|
|
for(int i = 0; i < possibleSteps.length; i++)
|
|
{
|
|
if(quests.isActive(possibleSteps[i], player))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::resetPlayer: -> System removed player from quest and quest step " + possibleSteps[i] + ". Quest timed out.", player, trace.TL_CS_LOG);
|
|
questGiver = getCurrentQuestGiver(player, possibleSteps[i]);
|
|
quests.deactivate(possibleSteps[i], player);
|
|
}
|
|
}
|
|
|
|
for (int x = 0; x < possibleSteps.length; x++)
|
|
{
|
|
if (quests.isComplete(possibleSteps[x], player))
|
|
{
|
|
clearCompletedQuest(player, quests.getQuestId(possibleSteps[x]));
|
|
}
|
|
}
|
|
|
|
if(hasObjVar(player, "fs_cs.returnCommanderWaypoint"))
|
|
{
|
|
destroyWaypointInDatapad(getObjIdObjVar(player, "fs_cs.returnCommanderWaypoint"), player);
|
|
}
|
|
|
|
removeObjVar(player, "fs_cs");
|
|
if(!hasScript(player, "systems.fs_quest.fs_cs_player"))
|
|
{
|
|
attachScript(player, "systems.fs_quest.fs_cs_player");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// clears all possible steps the player may be on and resets them to the beginning quest.
|
|
//
|
|
void resetPlayerToStart(obj_id player, obj_id questGiver)
|
|
{
|
|
string[] possibleSteps = new string[]
|
|
{
|
|
"fs_cs_intro",
|
|
"fs_cs_kill5_guards",
|
|
"fs_cs_ensure_capture",
|
|
"fs_cs_last_chance",
|
|
"fs_cs_escort_commander_pri",
|
|
"fs_cs_escort_commander_sec",
|
|
"fs_cs_quest_done",
|
|
"fs_cs_quest_failed_escort"
|
|
};
|
|
|
|
for(int i = 0; i < possibleSteps.length; i++)
|
|
{
|
|
if(quests.isActive(possibleSteps[i], player))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::resetPlayerToStart: -> Player was still in active quest step " + possibleSteps[i], player, trace.TL_WARNING);
|
|
questGiver = getCurrentQuestGiver(player, possibleSteps[i]);
|
|
quests.complete(possibleSteps[i], player, false);
|
|
}
|
|
|
|
clearCompletedQuest(player, quests.getQuestId(possibleSteps[i]));
|
|
}
|
|
|
|
destroyCommanderRescueWaypoint(player);
|
|
removeObjVar(player, "fs_cs");
|
|
quests.activate("fs_cs_intro", player, questGiver);
|
|
return;
|
|
}
|
|
|
|
|
|
void destroyCommanderRescueWaypoint(obj_id player)
|
|
{
|
|
if(hasObjVar(player, "fs_cs.returnCommanderWaypoint"))
|
|
{
|
|
destroyWaypointInDatapad(getObjIdObjVar(player, "fs_cs.returnCommanderWaypoint"), player);
|
|
removeObjVar(player, "fs_cs.returnCommanderWaypoint");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
boolean isShortCommanderRescue()
|
|
{
|
|
string config = getConfigSetting("GameServer", "FS_P3_ShortCommanderRescue");
|
|
if(config != null)
|
|
{
|
|
if(toLower(config).equals("true") || config.equals("1"))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
float getCampResetTime()
|
|
{
|
|
string config = getConfigSetting("GameServer", "FS_P3_CampResetTime");
|
|
if(config == null)
|
|
{
|
|
return CAMP_SHIELD_REBOOT_TIME;
|
|
}
|
|
|
|
int value = utils.stringToInt(config);
|
|
if(value > 0)
|
|
{
|
|
return (float)value;
|
|
}
|
|
|
|
return CAMP_SHIELD_REBOOT_TIME;
|
|
}
|
|
|
|
float getCampBossDeathTime()
|
|
{
|
|
string config = getConfigSetting("GameServer", "FS_P3_CampBossDeathTime");
|
|
if(config == null)
|
|
{
|
|
return CAMP_BOSS_DEATH_TIME;
|
|
}
|
|
|
|
int value = utils.stringToInt(config);
|
|
if(value > 0)
|
|
{
|
|
return (float)value;
|
|
}
|
|
|
|
return CAMP_BOSS_DEATH_TIME;
|
|
}
|
|
|
|
|
|
//
|
|
// marks creation time on an item
|
|
//
|
|
void markPhaseItemCreated(obj_id item)
|
|
{
|
|
setObjVar(item, OBJVAR_BORN_ON, getGameTime());
|
|
return;
|
|
}
|
|
|
|
//
|
|
// checks to see if the phase item needs to be disabled and then does so if it s
|
|
//
|
|
void checkPhaseItemDisable(obj_id item, int phase)
|
|
{
|
|
if(getPhaseItemPercentDecay(item, phase) >= 100)
|
|
{
|
|
setCondition(item, CONDITION_DISABLED);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// returns a whole number indicating the % of decay on the item
|
|
//
|
|
int getPhaseItemPercentDecay(obj_id item, int phase)
|
|
{
|
|
if(!hasObjVar(item, OBJVAR_BORN_ON))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int bornOn = getIntObjVar(item, OBJVAR_BORN_ON);
|
|
int now = getGameTime();
|
|
float phaseDuration = fs_dyn_village.getPhaseDuration(phase);
|
|
float itemAge = now - bornOn;
|
|
int percentDecay = (int)((itemAge/phaseDuration) * 100);
|
|
|
|
// sanity check
|
|
if(percentDecay > 100)
|
|
{
|
|
percentDecay = 100;
|
|
}
|
|
|
|
return percentDecay;
|
|
}
|
|
|
|
//
|
|
// returns a vector with 2 elements [0] = all locs; [1] = all names
|
|
// as the theatre construction may place the forts at a slightly different location
|
|
//
|
|
Vector getAllCampHintsFromDT()
|
|
{
|
|
int numRows = dataTableGetNumRows(DT_TABLE_NAME);
|
|
Vector locs = new Vector();
|
|
Vector names = new Vector();
|
|
|
|
dictionary curRow = null;
|
|
location loc = null;
|
|
|
|
for(int i = 0; i < numRows; i++)
|
|
{
|
|
// camp_names locs_x locs_y locs_z
|
|
curRow = dataTableGetRow(DT_TABLE_NAME, i);
|
|
if(!curRow.containsKey("camp_names") || !curRow.containsKey("locs_x") || !curRow.containsKey("locs_y") || !curRow.containsKey("locs_z"))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::getAllFortHintsFromDT: -> Bad data table data. Skipping row " + i, null, trace.TL_ERROR_LOG);
|
|
continue;
|
|
}
|
|
|
|
names.add(curRow.getString("camp_names"));
|
|
loc = new location(curRow.getFloat("locs_x"), curRow.getFloat("locs_y"), curRow.getFloat("locs_z"));
|
|
locs.add(loc);
|
|
}
|
|
|
|
|
|
Vector rslt = new Vector();
|
|
rslt.add(locs);
|
|
rslt.add(names);
|
|
|
|
return rslt;
|
|
}
|
|
|
|
int getMaxCampsPerCycle()
|
|
{
|
|
string config = getConfigSetting("GameServer", "FS_MaxPhase3EnemyCamps");
|
|
int value = utils.stringToInt(config);
|
|
if (value > 0)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
return MAX_NUM_CAMPS_PER_CYCLE;
|
|
}
|
|
|
|
boolean isOnCsQuest(obj_id player)
|
|
{
|
|
return quests.isActive("fs_cs_intro", player) ||
|
|
quests.isActive("fs_cs_kill5_guards", player) ||
|
|
quests.isActive("fs_cs_ensure_capture", player) ||
|
|
quests.isActive("fs_cs_last_chance", player) ||
|
|
quests.isActive("fs_cs_escort_commander_sec", player) ||
|
|
quests.isActive("fs_cs_quest_done", player) ||
|
|
quests.isActive("fs_cs_escort_commander_pri", player);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// method reads a data table and picks MAX_NUM_CAMPS_PER_CYCLE from the list and writes them to the master
|
|
//
|
|
void pickAndWriteCycleNamesAndLocs(obj_id villageMaster)
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Updating location hints and names used for this cycle.");
|
|
// get previously chosen camp names and loc hints that may or may not have been chosen previously
|
|
Vector phaseNames = new Vector();
|
|
Vector phaseLocs = new Vector();
|
|
|
|
if(hasObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES))
|
|
{
|
|
phaseNames = getResizeableStringArrayObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES);
|
|
}
|
|
|
|
if(hasObjVar(villageMaster, OBJVAR_PHASE_CAMP_LOC_HINTS))
|
|
{
|
|
phaseLocs = getResizeableLocationArrayObjVar(villageMaster, OBJVAR_PHASE_CAMP_LOC_HINTS);
|
|
}
|
|
|
|
if(phaseNames == null || phaseLocs == null || phaseNames.size() != phaseLocs.size())
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::pickAndWriteCycleNamesAndLocs: created camp names.length=" + phaseNames.size() + ", locs=" + phaseLocs.size() +".",
|
|
villageMaster, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
int maxCamps = getMaxCampsPerCycle();
|
|
while(phaseNames.size() > maxCamps)
|
|
{
|
|
phaseNames.removeElementAt(0);
|
|
phaseLocs.removeElementAt(0);
|
|
}
|
|
|
|
// get the complete set of names and location hints available from the datatable
|
|
Vector campsDat = getAllCampHintsFromDT();
|
|
if(campsDat.size() != 2)
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::pickAndWriteCycleNamesAndLocs: -> getAllCampHints returned badly structured data. Camps not determine camp info for this cycle.", null, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
// these are the data table hints of locs and names available for camps
|
|
Vector locs = (Vector)campsDat.get(0);
|
|
Vector names = (Vector)campsDat.get(1);
|
|
|
|
|
|
trace.log(fs_dyn_village.LOG_CHAN, "DT has " + locs.size() + " locs and " + names.size() + " names.");
|
|
// remove any previously chosen names and locs from the pool of availables
|
|
int idx = -1;
|
|
for(int i = 0; i < phaseNames.size(); i++)
|
|
{
|
|
// remove name
|
|
idx = names.indexOf(phaseNames.get(i));
|
|
if(idx > -1)
|
|
{
|
|
names.removeElementAt(idx);
|
|
}
|
|
|
|
// remove loc
|
|
idx = locs.indexOf(phaseLocs.get(i));
|
|
if(idx > -1)
|
|
{
|
|
locs.removeElementAt(idx);
|
|
}
|
|
}
|
|
|
|
// pick any additional phase locs/names based on maxCamps
|
|
for(int x = 0; phaseNames.size() < maxCamps && names.size() > 0; x++)
|
|
{
|
|
idx = rand(0, locs.size() -1);
|
|
phaseLocs.add(locs.get(idx));
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Camp LOC " + phaseLocs.size() + " for this cycle is " + locs.get(idx).toString());
|
|
locs.removeElementAt(idx);
|
|
reseed(getGameTime() + idx + 222);
|
|
|
|
idx = rand(0, names.size() - 1);
|
|
phaseNames.add(names.get(idx));
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Camp NAME " + phaseNames.size() + " for this cycle is " + names.get(idx).toString());
|
|
names.removeElementAt(idx);
|
|
reseed(getGameTime() + idx + 777);
|
|
}
|
|
|
|
trace.log(fs_dyn_village.LOG_CHAN, "_picknames: phaseNames.size()=" + phaseNames.size() + ", phaseLocs.size()=" + phaseLocs.size());
|
|
setObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES, phaseNames);
|
|
setObjVar(villageMaster, OBJVAR_PHASE_CAMP_LOC_HINTS, phaseLocs);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// creates all of the theatres for this phase and starts the registration process with the village master
|
|
//
|
|
void initializeEnemyCamps(obj_id villageMaster)
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Init Enemy Camps.");
|
|
// make sure we have our camp name and location hints written out
|
|
pickAndWriteCycleNamesAndLocs(villageMaster);
|
|
|
|
// create the camps and write the obj_ids of the theatre master objects to the village master
|
|
_createEnemyCamps(villageMaster);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// creates all village enemy camps for the current cycle.
|
|
//
|
|
void _createEnemyCamps(obj_id villageMaster)
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Creating Enemy Camps from hint data.");
|
|
Vector phaseLocs = new Vector();
|
|
Vector phaseNames = new Vector();
|
|
|
|
if(hasObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES))
|
|
{
|
|
phaseNames = getResizeableStringArrayObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES);
|
|
}
|
|
|
|
if(hasObjVar(villageMaster, OBJVAR_PHASE_CAMP_LOC_HINTS))
|
|
{
|
|
phaseLocs = getResizeableLocationArrayObjVar(villageMaster, OBJVAR_PHASE_CAMP_LOC_HINTS);
|
|
}
|
|
|
|
trace.log(fs_dyn_village.LOG_CHAN, "_createEnemeyCamps: phaseNames null=" + (phaseNames == null));
|
|
trace.log(fs_dyn_village.LOG_CHAN, "_createEnemeyCamps: phaseLocs null=" + (phaseLocs == null));
|
|
if(phaseNames == null || phaseLocs == null || phaseNames.size() != phaseLocs.size())
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN,
|
|
"fs_counterstrike::_createEnemyCamps: -> phaseNames.size != phaseLocs.size - cannot create enemy camp. Data mismatch.", villageMaster, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < phaseLocs.size(); i++)
|
|
{
|
|
boolean rslt = createRemoteTheater(DT_TABLE_POI_NAME, (location)phaseLocs.get(i), "systems.fs_quest.fs_outpost_master", villageMaster, (string)phaseNames.get(i), TLT_none);
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Attempting (" + rslt + ") to create theatre " + (string)phaseNames.get(i) + " at idx " + i + " at location " + (location)phaseLocs.get(i));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void theatreDestroyed(obj_id villageMaster, obj_id destroyedCamp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// writes a camp's location to the village master. locations are kept in scriptvars
|
|
// as the camp registers itself everytime it initializes. camps with location
|
|
// are considered "clean" and have been authorized to function
|
|
// @returns the string name of the camp for which the location was set
|
|
//
|
|
string setLocForCamp(obj_id villageMaster, obj_id campId, location loc, string campName)
|
|
{
|
|
string rslt = "";
|
|
if(!isIdValid(villageMaster) || !exists(villageMaster))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::setLocForCamp: -> villageMaster is invalid or doesn't exist. location not set for campId " + campId + ".",
|
|
villageMaster, trace.TL_ERROR_LOG);
|
|
return rslt;
|
|
}
|
|
|
|
Vector names = new Vector();
|
|
// grab the names for use during this phase
|
|
if(hasObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES))
|
|
{
|
|
names = getResizeableStringArrayObjVar(villageMaster, OBJVAR_PHASE_CAMP_NAMES);
|
|
}
|
|
|
|
int nameIdx = names.indexOf(campName);
|
|
if(nameIdx < 0)
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::setLocForCamp: -> could not find camp name " + campName + ", not registering camp " + campId + ".",
|
|
villageMaster, trace.TL_ERROR_LOG);
|
|
return rslt;
|
|
}
|
|
|
|
location[] locs = new location[names.size()];
|
|
obj_id[] campIds = new obj_id[names.size()];
|
|
|
|
// grab any previously registered camp objIds
|
|
if(utils.hasScriptVar(villageMaster, OBJVAR_CREATED_CAMP_IDS))
|
|
{
|
|
campIds = utils.getObjIdArrayScriptVar(villageMaster, OBJVAR_CREATED_CAMP_IDS);
|
|
if(campIds == null || campIds.length != names.size())
|
|
{
|
|
utils.removeScriptVar(villageMaster, OBJVAR_CREATED_CAMP_IDS);
|
|
campIds = new obj_id[names.size()];
|
|
}
|
|
}
|
|
|
|
// grab any previously registered camp locations
|
|
if(utils.hasScriptVar(villageMaster, OBJVAR_CREATED_CAMP_LOCS))
|
|
{
|
|
locs = utils.getLocationArrayScriptVar(villageMaster, OBJVAR_CREATED_CAMP_LOCS);
|
|
if(locs == null || locs.length != names.size())
|
|
{
|
|
utils.removeScriptVar(villageMaster, OBJVAR_CREATED_CAMP_LOCS);
|
|
locs = new location[names.size()];
|
|
}
|
|
}
|
|
|
|
//if the name is already taken by another campm refuse this one
|
|
if(isIdValid(campIds[nameIdx]))
|
|
{
|
|
return ""; // empy string is a failure
|
|
}
|
|
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Registering " + campId + " as " + campName + " at location " + loc.toString());
|
|
locs[nameIdx] = loc;
|
|
campIds[nameIdx] = campId;
|
|
|
|
utils.setScriptVar(villageMaster, OBJVAR_CREATED_CAMP_LOCS, locs);
|
|
utils.setScriptVar(villageMaster, OBJVAR_CREATED_CAMP_IDS, campIds);
|
|
rslt = (string)names.get(nameIdx);
|
|
|
|
return rslt;
|
|
}
|
|
|
|
void failQuestForCampers(obj_id campId)
|
|
{
|
|
// if there is a commander, the easiest thing to do is kill him. doesnt break the story as much
|
|
obj_id commander = null;
|
|
if(hasObjVar(campId, OBJVAR_CAMP_COMMANDER))
|
|
{
|
|
commander = getObjIdObjVar(campId, OBJVAR_CAMP_COMMANDER);
|
|
messageTo(commander, "msgLifeExpired", null, 0.0f, false);
|
|
return;
|
|
}
|
|
|
|
// we need to check if the shield has been powered down. if so fail them
|
|
obj_id shieldKiller = null;
|
|
if(hasObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER))
|
|
{
|
|
shieldKiller = getObjIdObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER);
|
|
messageTo(shieldKiller, "msgShieldPowerup", null, 0.0f, false);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
///
|
|
/// resets a camp to new condition, like nothing ever happened.
|
|
///
|
|
void resetCamp(obj_id campId, boolean recreate)
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "Resetting camp " + campId);
|
|
failQuestForCampers(campId);
|
|
// a bunch of objvars need to be here to recreate the camp, else we need to destroy it
|
|
// ugly - need to rewrite this to be more generic for an arbitrary number of trackable objects...
|
|
if(
|
|
!hasObjVar(campId, OBJVAR_CAMP_DOOR1) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_DOOR1_LOC) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_DOOR1_YAW) ||
|
|
|
|
!hasObjVar(campId, OBJVAR_CAMP_DOOR2) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_DOOR2_LOC) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_DOOR2_YAW) ||
|
|
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET1) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET1_LOC) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET1_YAW) ||
|
|
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET2) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET2_LOC) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET2_YAW) ||
|
|
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET3) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET3_LOC) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_TURRET3_YAW) ||
|
|
|
|
!hasObjVar(campId, OBJVAR_CAMP_ANTENNA) ||
|
|
!hasObjVar(campId, OBJVAR_CAMP_ANTENNA_LOC)
|
|
)
|
|
{
|
|
destroyObject(campId);
|
|
return;
|
|
}
|
|
|
|
// put the shield back up
|
|
erectShield();
|
|
|
|
// recreate Turret1
|
|
obj_id turret1 = getObjIdObjVar(campId, OBJVAR_CAMP_TURRET1);
|
|
if(isIdValid(turret1) && exists(turret1))
|
|
{
|
|
destroyObject(turret1);
|
|
}
|
|
|
|
if(recreate)
|
|
{
|
|
turret1 = create.object(CAMP_TURRET_TEMPLATE, getLocationObjVar(campId, OBJVAR_CAMP_TURRET1_LOC));
|
|
if(isIdValid(turret1))
|
|
{
|
|
setYaw(turret1, getFloatObjVar(campId, OBJVAR_CAMP_TURRET1_YAW));
|
|
setObjVar(campId, OBJVAR_CAMP_TURRET1, turret1);
|
|
setInvulnerable(turret1, false);
|
|
setObjVar(turret1, turret.OBJVAR_CAN_ATTACK, "allPlayers");
|
|
}
|
|
else
|
|
{
|
|
destroyObject(campId);
|
|
}
|
|
}
|
|
|
|
// recreate Turret2
|
|
obj_id turret2 = getObjIdObjVar(campId, OBJVAR_CAMP_TURRET2);
|
|
if(isIdValid(turret2) && exists(turret2))
|
|
{
|
|
destroyObject(turret2);
|
|
}
|
|
|
|
if(recreate)
|
|
{
|
|
turret2= create.object(CAMP_TURRET_TEMPLATE, getLocationObjVar(campId, OBJVAR_CAMP_TURRET2_LOC));
|
|
if(isIdValid(turret2))
|
|
{
|
|
setYaw(turret2, getFloatObjVar(campId, OBJVAR_CAMP_TURRET2_YAW));
|
|
setObjVar(campId, OBJVAR_CAMP_TURRET2, turret2);
|
|
setInvulnerable(turret2, false);
|
|
setObjVar(turret2, turret.OBJVAR_CAN_ATTACK, "allPlayers");
|
|
}
|
|
else
|
|
{
|
|
destroyObject(campId);
|
|
}
|
|
}
|
|
|
|
// recreate Turret3
|
|
obj_id turret3 = getObjIdObjVar(campId, OBJVAR_CAMP_TURRET3);
|
|
if(isIdValid(turret3) && exists(turret3))
|
|
{
|
|
destroyObject(turret3);
|
|
}
|
|
|
|
if(recreate)
|
|
{
|
|
turret3= create.object(CAMP_TURRET_TEMPLATE, getLocationObjVar(campId, OBJVAR_CAMP_TURRET3_LOC));
|
|
if(isIdValid(turret3))
|
|
{
|
|
setYaw(turret3, getFloatObjVar(campId, OBJVAR_CAMP_TURRET3_YAW));
|
|
setObjVar(campId, OBJVAR_CAMP_TURRET3, turret3);
|
|
setInvulnerable(turret3, false);
|
|
setObjVar(turret3, turret.OBJVAR_CAN_ATTACK, "allPlayers");
|
|
}
|
|
else
|
|
{
|
|
destroyObject(campId);
|
|
}
|
|
}
|
|
|
|
// recreate door 1
|
|
obj_id door1 = getObjIdObjVar(campId, OBJVAR_CAMP_DOOR1);
|
|
if(isIdValid(door1) && exists(door1))
|
|
{
|
|
destroyObject(door1);
|
|
}
|
|
|
|
if(recreate)
|
|
{
|
|
door1 = create.object(CAMP_DOOR_TEMPLATE, getLocationObjVar(campId, OBJVAR_CAMP_DOOR1_LOC));
|
|
if(isIdValid(door1))
|
|
{
|
|
setYaw(door1, getFloatObjVar(campId, OBJVAR_CAMP_DOOR1_YAW));
|
|
setObjVar(campId, OBJVAR_CAMP_DOOR1, door1);
|
|
setInvulnerable(door1, true);
|
|
detachScript(door1, "systems.battlefield.destructible_building");
|
|
attachScript(door1, "systems.fs_quest.destructible_obj");
|
|
}
|
|
else
|
|
{
|
|
destroyObject(campId);
|
|
}
|
|
}
|
|
|
|
// recreate door 2
|
|
obj_id door2 = getObjIdObjVar(campId, OBJVAR_CAMP_DOOR2);
|
|
if(isIdValid(door2) && exists(door2))
|
|
{
|
|
destroyObject(door2);
|
|
}
|
|
|
|
if(recreate)
|
|
{
|
|
door2 = create.object(CAMP_DOOR_TEMPLATE, getLocationObjVar(campId, OBJVAR_CAMP_DOOR2_LOC));
|
|
if(isIdValid(door1))
|
|
{
|
|
setYaw(door2, getFloatObjVar(campId, OBJVAR_CAMP_DOOR2_YAW));
|
|
setObjVar(campId, OBJVAR_CAMP_DOOR2, door2);
|
|
setInvulnerable(door2, true);
|
|
detachScript(door2, "systems.battlefield.destructible_building");
|
|
attachScript(door2, "systems.fs_quest.destructible_obj");
|
|
}
|
|
else
|
|
{
|
|
destroyObject(campId);
|
|
}
|
|
}
|
|
// recreate antenna
|
|
obj_id antenna = getObjIdObjVar(campId, OBJVAR_CAMP_ANTENNA);
|
|
if(isIdValid(antenna) && exists(antenna))
|
|
{
|
|
destroyObject(antenna);
|
|
}
|
|
|
|
if(recreate)
|
|
{
|
|
antenna = create.object(CAMP_ANTENNA_TEMPLATE, getLocationObjVar(campId, OBJVAR_CAMP_ANTENNA_LOC));
|
|
if(isIdValid(antenna))
|
|
{
|
|
setObjVar(campId, OBJVAR_CAMP_ANTENNA, antenna);
|
|
setInvulnerable(antenna, true);
|
|
detachScript(antenna, "systems.battlefield.destructible_building");
|
|
attachScript(antenna, "systems.fs_quest.destructible_obj");
|
|
}
|
|
else
|
|
{
|
|
destroyObject(campId);
|
|
}
|
|
}
|
|
|
|
if(hasObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER))
|
|
{
|
|
removeObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER);
|
|
}
|
|
|
|
if(hasObjVar(campId, OBJVAR_STOP_DEFENSE_SPAWN))
|
|
{
|
|
removeObjVar(campId, OBJVAR_STOP_DEFENSE_SPAWN);
|
|
}
|
|
|
|
if(hasObjVar(campId, OBJVAR_CAMP_COMMANDER))
|
|
{
|
|
removeObjVar(campId, OBJVAR_CAMP_COMMANDER);
|
|
}
|
|
|
|
if(hasObjVar(campId, OBJVAR_CAMP_COMMANDER_TAKER))
|
|
{
|
|
removeObjVar(campId, OBJVAR_CAMP_COMMANDER_TAKER);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// checks to see if the antenna has been destroyed or not
|
|
//
|
|
boolean antennaExists(obj_id campId)
|
|
{
|
|
boolean rslt = false;
|
|
if(hasObjVar(campId, OBJVAR_CAMP_ANTENNA))
|
|
{
|
|
obj_id antenna = getObjIdObjVar(campId, OBJVAR_CAMP_ANTENNA);
|
|
if(isIdValid(antenna) && exists(antenna))
|
|
{
|
|
rslt = true;
|
|
}
|
|
}
|
|
|
|
return rslt;
|
|
}
|
|
|
|
//
|
|
// construct spawn wave definition based on number of players in the area
|
|
//
|
|
string[] getSpawnWaves(obj_id campId)
|
|
{
|
|
int numPlayers = 1;
|
|
obj_id[] players = getPlayerCreaturesInRange(campId, 100.0f);
|
|
if(players != null)
|
|
{
|
|
numPlayers = players.length;
|
|
}
|
|
|
|
string[] spawnWaves = new string[]{"fs_counterstrike_small"};
|
|
|
|
if(numPlayers > 10)
|
|
{
|
|
if(antennaExists(campId))
|
|
{
|
|
spawnWaves = new string[]{"fs_counterstrike_small", "fs_counterstrike_medium"};
|
|
}
|
|
else
|
|
{
|
|
spawnWaves = new string[]{"fs_counterstrike_medium"};
|
|
}
|
|
}
|
|
|
|
if(numPlayers > 20)
|
|
{
|
|
if(antennaExists(campId))
|
|
{
|
|
spawnWaves = new string[]{"fs_counterstrike_small", "fs_counterstrike_small", "fs_counterstrike_medium"};
|
|
}
|
|
else
|
|
{
|
|
spawnWaves = new string[]{"fs_counterstrike_small", "fs_counterstrike_medium"};
|
|
}
|
|
}
|
|
|
|
if(numPlayers > 30)
|
|
{
|
|
if(antennaExists(campId))
|
|
{
|
|
spawnWaves = new string[]{"fs_counterstrike_small", "fs_counterstrike_small", "fs_counterstrike_medium", "fs_counterstrike_medium"};
|
|
}
|
|
else
|
|
{
|
|
spawnWaves = new string[]{"fs_counterstrike_small", "fs_counterstrike_small", "fs_counterstrike_medium"};
|
|
}
|
|
}
|
|
|
|
|
|
return spawnWaves;
|
|
}
|
|
|
|
//
|
|
// generates a spawn wave to defend the camp
|
|
//
|
|
void doCampDefenseSpawn(obj_id campId, boolean scheduleNext)
|
|
{
|
|
if(hasObjVar(campId, OBJVAR_STOP_DEFENSE_SPAWN) || !hasObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!isIdValid(campId) || !exists(campId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
long seed = campId.getValue();
|
|
while(seed > Integer.MAX_VALUE)
|
|
{
|
|
seed /= 2;
|
|
}
|
|
|
|
reseed((int)seed);
|
|
|
|
string wave = "";
|
|
float heading = 0.0f;
|
|
location spawnerLoc = null;
|
|
location masterLoc = getLocation(campId);
|
|
obj_id spawner = null;
|
|
string[] spawnWaves = getSpawnWaves(campId);
|
|
|
|
for(int i = 0; i < spawnWaves.length; i++)
|
|
{
|
|
wave = spawnWaves[i];
|
|
spawnerLoc = utils.getRandomAwayLocation(masterLoc, 50.0f, 110.0f);
|
|
spawner = quests.createSpawner(wave, spawnerLoc, fs_dyn_village.CITY_BAD_GUY_SPAWN_TABLE, campId);
|
|
if(isIdValid(spawner))
|
|
{
|
|
seed = spawner.getValue();
|
|
while(seed > Integer.MAX_VALUE)
|
|
{
|
|
seed /= 2;
|
|
}
|
|
|
|
setObjVar(spawner, OBJVAR_MY_CAMP_ID, campId);
|
|
}
|
|
reseed((int)seed);
|
|
}
|
|
|
|
if(scheduleNext)
|
|
{
|
|
messageTo(campId, "msgDoCampDefenseSpawn", null, (float)rand(CAMP_REINFORCEMENT_MIN, CAMP_REINFORCEMENT_MAX), false);
|
|
}
|
|
}
|
|
|
|
//
|
|
// erects the shield around the camp
|
|
//
|
|
void erectShield()
|
|
{
|
|
obj_id me = getSelf();
|
|
if(!hasScript(me, "systems.fs_quest.fs_outpost_master"))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::erectShield: -> can only erect shields for enemy camps. " + me + " is not a camp master.",
|
|
me, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
location here = getLocation(me);
|
|
if(!hasTriggerVolume(me, SHIELD_TR_VOLUME))
|
|
{
|
|
createTriggerVolume(SHIELD_TR_VOLUME, SHIELD_RADIUS, true);
|
|
}
|
|
|
|
//trace.log(fs_dyn_village.LOG_CHAN, "Shield erected for " + me);
|
|
|
|
obj_id[] intruders = getCreaturesInRange(here, SHIELD_RADIUS + 1);
|
|
for(int i = 0; i < intruders.length; i++)
|
|
{
|
|
//trace.log(fs_dyn_village.LOG_CHAN, "Expelling " + intruders[i] + " , template " + getTemplateName(intruders[i]) + " from camp.");
|
|
sendSystemMessage(intruders[i], new string_id("fs_quest_village","expel_shield"));
|
|
if(!isGod(intruders[i]) && !hasScript(intruders[i], "systems.fs_quest.fs_camp_commander_ai"))
|
|
{
|
|
expelFromTriggerVolume(me, SHIELD_TR_VOLUME, intruders[i]);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// checks to see if two players in groups
|
|
//
|
|
boolean arePlayersInSameGroup(obj_id player1, obj_id player2)
|
|
{
|
|
obj_id group = getGroupObject(player1);
|
|
if(!isIdValid(group))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
obj_id[] members = getGroupMemberIds(group);
|
|
if(utils.getElementPositionInArray(members, player2) > -1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// checks to see if the shield generator is nearby and wether or not the shield can be powered down
|
|
//
|
|
boolean attemptPowerDownShield(obj_id player, string remoteId)
|
|
{
|
|
// cant do it in a city. too much garbage around
|
|
if(locations.isInCity(getLocation(player)))
|
|
{
|
|
sendSystemMessage(player, new string_id("fs_quest_village","shield_remote_interference"));
|
|
return false;
|
|
}
|
|
|
|
if(!allowedToPowerDownShield(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("fs_quest_village","shield_remote_cant_use"));
|
|
return false;
|
|
}
|
|
|
|
obj_id[] stuff = getNonCreaturesInRange(getLocation(player), SHIELD_REMOTE_RANGE);
|
|
for(int t = 0; t < stuff.length; t++)
|
|
{
|
|
if(hasObjVar(stuff[t], OBJVAR_IS_REMOTE_RECEIVER))
|
|
{
|
|
obj_id campMaster = getMyOutpostId(stuff[t]);
|
|
if(campMaster == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(!hasTriggerVolume(campMaster, SHIELD_TR_VOLUME))
|
|
{
|
|
sendSystemMessage(player, new string_id("fs_quest_village","remote_shield_down_already"));
|
|
return false;
|
|
}
|
|
|
|
if(hasObjVar(campMaster, OBJVAR_CAMP_NAME))
|
|
{
|
|
if(getStringObjVar(campMaster, OBJVAR_CAMP_NAME).equals(remoteId))
|
|
{
|
|
setObjVar(campMaster, OBJVAR_CAMP_SHIELD_KILLER, player);
|
|
|
|
if(group.isGrouped(player))
|
|
{
|
|
obj_id[] gang = null;
|
|
gang = getGroupMemberIds(getGroupObject(player));
|
|
|
|
if((gang != null) && (gang.length > 0) )
|
|
{
|
|
for(int g = 0; g < gang.length; g++)
|
|
{
|
|
obj_id thisGuy = gang[g];
|
|
if(isIdValid(thisGuy) && exists(thisGuy) && thisGuy != player)
|
|
{
|
|
sendSystemMessage(thisGuy, new string_id("fs_quest_village", "remote_powering_down"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// player gets his message here, just in case something wonky is going on with groups
|
|
sendSystemMessage(player, new string_id("fs_quest_village","remote_powering_down"));
|
|
|
|
messageTo(campMaster, "msgPowerDownShield", null, 0.0f, false);
|
|
|
|
obj_id questGiver = getCurrentQuestGiver(player, "fs_cs_intro");
|
|
quests.complete("fs_cs_intro", player, true);
|
|
quests.activate("fs_cs_kill5_guards", player, questGiver);
|
|
setObjVar(player, OBJVAR_MY_CAMP_ID, campMaster);
|
|
sendSystemMessage(player, new string_id("fs_quest_village", "fs_cs_step_intro_complete"));
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
sendSystemMessage(player, new string_id("fs_quest_village","shield_remote_wrong_camp"));
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sendSystemMessage(player, new string_id("fs_quest_village","remote_nothing_happens"));
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// checks to see if a person is on the quest or not
|
|
//
|
|
boolean allowedToPowerDownShield(obj_id player)
|
|
{
|
|
// ToDo: perform check!
|
|
if(quests.isActive("fs_cs_intro", player))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// creates a camp's commander
|
|
//
|
|
obj_id createCommander(obj_id campId)
|
|
{
|
|
obj_id commander = null;
|
|
|
|
if(hasObjVar(campId, OBJVAR_CAMP_COMMANDER))
|
|
{
|
|
commander = getObjIdObjVar(campId, OBJVAR_CAMP_COMMANDER);
|
|
messageTo(campId, "msgLifeExpired", null, 0.0f, false);
|
|
}
|
|
|
|
obj_id shieldKiller = null;
|
|
if(hasObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER))
|
|
{
|
|
shieldKiller = getObjIdObjVar(campId, OBJVAR_CAMP_SHIELD_KILLER);
|
|
}
|
|
|
|
if(!hasObjVar(campId, OBJVAR_CAMP_TENT_LOC))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::createCommnader: -> Error creating camp commander (missing " + OBJVAR_CAMP_TENT_LOC + ") for camp " + campId +
|
|
"Quest cannot complete. Person who powered down shield was " + shieldKiller, shieldKiller, trace.TL_ERROR_LOG | trace.TL_CS_LOG);
|
|
return null;
|
|
}
|
|
|
|
location here = getLocationObjVar(campId, OBJVAR_CAMP_TENT_LOC);
|
|
|
|
commander = create.object("shadow_mercenary_nofaction", here);
|
|
if(isIdValid(commander))
|
|
{
|
|
setInvulnerable(commander, true);
|
|
setHomeLocation(commander, here);
|
|
setMovementRun(commander);
|
|
applySkillStatisticModifier(commander, "slope_move", 50);
|
|
setObjVar(campId, OBJVAR_CAMP_COMMANDER, commander);
|
|
setObjVar(commander, OBJVAR_CAMP_SHIELD_KILLER, shieldKiller);
|
|
setObjVar(commander, OBJVAR_MY_CAMP_ID, campId);
|
|
attachScript(commander, "systems.fs_quest.fs_camp_commander_ai");
|
|
}
|
|
else
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::createCommnader: -> Error creating camp commander for camp " + campId +
|
|
"Quest cannot complete. Person who powered down shield was " + shieldKiller, shieldKiller, trace.TL_ERROR_LOG | trace.TL_CS_LOG);
|
|
}
|
|
|
|
return commander;
|
|
}
|
|
|
|
|
|
//
|
|
// reads quests.libbrary quest data to get the current quest giver, so we can pass it on to the next step
|
|
//
|
|
obj_id getCurrentQuestGiver(obj_id player, string questName)
|
|
{
|
|
obj_id questGiver = null;
|
|
string objvarname = "questlib." + questName + ".quest_giver";
|
|
if(hasObjVar(player, objvarname))
|
|
{
|
|
questGiver = getObjIdObjVar(player, objvarname);
|
|
}
|
|
|
|
return questGiver;
|
|
}
|
|
|
|
//
|
|
// removes the shield around the camp -- !! only to be called by camp master !!
|
|
//
|
|
void powerDownShield()
|
|
{
|
|
obj_id me = getSelf();
|
|
if(!hasScript(me, "systems.fs_quest.fs_outpost_master"))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::powerDownShield: -> can only power down shields for enemy camps. " + me + " is not a camp master.",
|
|
me, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
location here = getLocation(me);
|
|
if(hasTriggerVolume(me, SHIELD_TR_VOLUME))
|
|
{
|
|
removeTriggerVolume(SHIELD_TR_VOLUME);
|
|
}
|
|
|
|
if(hasObjVar(me, OBJVAR_CAMP_DOOR1))
|
|
{
|
|
obj_id door1 = getObjIdObjVar(me, OBJVAR_CAMP_DOOR1);
|
|
if(isIdValid(door1))
|
|
{
|
|
setInvulnerable(door1, false);
|
|
}
|
|
}
|
|
|
|
if(hasObjVar(me, OBJVAR_CAMP_DOOR2))
|
|
{
|
|
obj_id door2 = getObjIdObjVar(me, OBJVAR_CAMP_DOOR2);
|
|
if(isIdValid(door2))
|
|
{
|
|
setInvulnerable(door2, false);
|
|
}
|
|
}
|
|
|
|
if(hasObjVar(me, OBJVAR_CAMP_ANTENNA))
|
|
{
|
|
obj_id antenna = getObjIdObjVar(me, OBJVAR_CAMP_ANTENNA);
|
|
if(isIdValid(antenna))
|
|
{
|
|
setInvulnerable(antenna, false);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// spawns some surveillance droid spawners that will kick off the
|
|
// droid population around the outpost
|
|
//
|
|
void spawnSurveillanceDroids(obj_id campMaster)
|
|
{
|
|
location here = getLocation(campMaster);
|
|
|
|
Vector existingDroids = new Vector();
|
|
if(hasObjVar(campMaster, OBJVAR_CAMP_DROIDS))
|
|
{
|
|
existingDroids = utils.getResizeableObjIdBatchObjVar(campMaster, OBJVAR_CAMP_DROIDS);
|
|
}
|
|
|
|
for(int x = 0; x < existingDroids.size(); x++)
|
|
{
|
|
messageTo((obj_id)existingDroids.get(x), "msgSilentSelfDestruct", null, 0.0f, false);
|
|
}
|
|
|
|
Vector newDroids = new Vector();
|
|
obj_id curDroid = null;
|
|
|
|
for(int i = 0; i < MAX_DROIDS_FOR_CAMP; i++)
|
|
{
|
|
curDroid = _createSingleDroid(campMaster, here);
|
|
if(isIdValid(curDroid))
|
|
{
|
|
newDroids.add(curDroid);
|
|
}
|
|
}
|
|
|
|
utils.setResizeableBatchObjVar(campMaster, OBJVAR_CAMP_DROIDS, newDroids);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// creates a single droid for a camp
|
|
//
|
|
obj_id _createSingleDroid(obj_id campMaster, location here)
|
|
{
|
|
location where = utils.getRandomAwayLocation(here, MIN_DROID_DISTANCE, MAX_DROID_DISTANCE);
|
|
obj_id curDroid = create.object("mouse_droid", where);
|
|
|
|
if(isIdValid(curDroid))
|
|
{
|
|
setObjVar(curDroid, OBJVAR_MY_CAMP_ID, campMaster);
|
|
string name = "test";
|
|
if(hasObjVar(campMaster, OBJVAR_CAMP_NAME))
|
|
{
|
|
name = getStringObjVar(campMaster, OBJVAR_CAMP_NAME);
|
|
}
|
|
setName(curDroid, new string_id("fs_quest_village", MOUSE_DROID_NAME_ID + name ));
|
|
attachScript(curDroid, "systems.fs_quest.fs_surveillance_droid");
|
|
}
|
|
|
|
//trace.log(fs_dyn_village.LOG_CHAN, "Created droid " + curDroid + " at " + where.toString());
|
|
return curDroid;
|
|
}
|
|
|
|
//
|
|
// removes dead droid from list and create a replacement
|
|
//
|
|
void droidDied(obj_id campMaster, obj_id deadDroid)
|
|
{
|
|
Vector existingDroids = new Vector();
|
|
if(hasObjVar(campMaster, OBJVAR_CAMP_DROIDS))
|
|
{
|
|
existingDroids = utils.getResizeableObjIdBatchObjVar(campMaster, OBJVAR_CAMP_DROIDS);
|
|
}
|
|
|
|
int idx = existingDroids.indexOf(deadDroid);
|
|
if(idx > -1)
|
|
{
|
|
existingDroids.removeElementAt(idx);
|
|
}
|
|
|
|
obj_id newDroid = _createSingleDroid(campMaster, getLocation(campMaster));
|
|
if(isIdValid(newDroid))
|
|
{
|
|
existingDroids.add(newDroid);
|
|
}
|
|
|
|
utils.setResizeableBatchObjVar(campMaster, OBJVAR_CAMP_DROIDS, existingDroids);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// scrubs the OBJVAR_CAMP_OBJS and sets the appropriate objvar/loc variables for easy lookup later
|
|
//
|
|
void registerCampObjIds(obj_id campMaster)
|
|
{
|
|
if(!isIdValid(campMaster))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::registerCampObjIds: -> Error scrubbing " + OBJVAR_CAMP_OBJS +
|
|
" for camp objids. Camp master is not valid.", campMaster, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
|
|
if(!exists(campMaster))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::registerCampObjIds: -> Error scrubbing " + OBJVAR_CAMP_OBJS +
|
|
" for camp objids. Camp master does not exist on this server.", campMaster, trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
|
|
if(!hasObjVar(campMaster, OBJVAR_CAMP_OBJS))
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::registerCampObjIds: -> Error scrubbing " + OBJVAR_CAMP_OBJS +
|
|
" for camp objids. Objvar missing. Nuking camp.", campMaster, trace.TL_ERROR_LOG);
|
|
destroyObject(campMaster);
|
|
}
|
|
|
|
obj_id[] objs = utils.getObjIdBatchObjVar(campMaster, OBJVAR_CAMP_OBJS);
|
|
|
|
string tName = "";
|
|
boolean foundFirstDoor = false;
|
|
int turretNum = 1;
|
|
for(int i = 0; i < objs.length; i++)
|
|
{
|
|
if(!isIdValid(objs[i]) || !exists(objs[i]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
tName = getTemplateName(objs[i]);
|
|
setObjVar(objs[i], OBJVAR_IS_REMOTE_RECEIVER, true);
|
|
setObjVar(objs[i], OBJVAR_MY_CAMP_ID, campMaster);
|
|
|
|
if(tName == null)
|
|
{
|
|
trace.log("fs_quest", "fs_counterstrike::registerCampObjIds: -> " + objs[i] + " has no template.");
|
|
continue;
|
|
}
|
|
|
|
if(tName.equals(CAMP_DOOR_TEMPLATE))
|
|
{
|
|
if(!foundFirstDoor)
|
|
{
|
|
setObjVar(campMaster, OBJVAR_CAMP_DOOR1, objs[i]);
|
|
setObjVar(campMaster, OBJVAR_CAMP_DOOR1_LOC, getLocation(objs[i]));
|
|
setObjVar(campMaster, OBJVAR_CAMP_DOOR1_YAW, getYaw(objs[i]));
|
|
foundFirstDoor = true;
|
|
}
|
|
else
|
|
{
|
|
setObjVar(campMaster, OBJVAR_CAMP_DOOR2, objs[i]);
|
|
setObjVar(campMaster, OBJVAR_CAMP_DOOR2_LOC, getLocation(objs[i]));
|
|
setObjVar(campMaster, OBJVAR_CAMP_DOOR2_YAW, getYaw(objs[i]));
|
|
}
|
|
|
|
detachScript(objs[i], "systems.battlefield.destructible_building");
|
|
attachScript(objs[i], "systems.fs_quest.destructible_obj");
|
|
setInvulnerable(objs[i], true);
|
|
}
|
|
else if(tName.equals(CAMP_ANTENNA_TEMPLATE))
|
|
{
|
|
setObjVar(campMaster, OBJVAR_CAMP_ANTENNA, objs[i]);
|
|
setObjVar(campMaster, OBJVAR_CAMP_ANTENNA_LOC, getLocation(objs[i]));
|
|
detachScript(objs[i], "systems.battlefield.destructible_building");
|
|
attachScript(objs[i], "systems.fs_quest.destructible_obj");
|
|
setInvulnerable(objs[i], true);
|
|
}
|
|
else if(tName.equals(CAMP_TURRET_TEMPLATE))
|
|
{
|
|
setObjVar(campMaster, "fs_cs.camp.turret" + turretNum, objs[i]);
|
|
setObjVar(campMaster, "fs_cs.camp.turret" + turretNum + "Loc", getLocation(objs[i]));
|
|
setObjVar(campMaster, "fs_cs.camp.turret" + turretNum + "Yaw", getYaw(objs[i]));
|
|
setObjVar(objs[i], turret.OBJVAR_CAN_ATTACK, "allPlayers"); // turrets attack anyone who's not a "friend" (turret.OBJVAR_TURRET_FRIEND)
|
|
turretNum++;
|
|
}
|
|
else if(tName.equals(CAMP_TENT_TEMPLATE))
|
|
{
|
|
setObjVar(campMaster, OBJVAR_CAMP_TENT_LOC, getLocation(objs[i]));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// performs initial camp setup only called when the theatre is first created.
|
|
//
|
|
void setupCamp(obj_id campMaster, boolean registerLocs)
|
|
{
|
|
if(!hasObjVar(campMaster, OBJVAR_CAMP_OBJS) || !hasObjVar(campMaster, OBJVAR_CAMP_NAME))
|
|
{
|
|
// camp is either not done being crated, or its not registered yet with the master object
|
|
return;
|
|
}
|
|
|
|
if(campMaster != getSelf())
|
|
{
|
|
trace.log(fs_dyn_village.LOG_CHAN, "fs_counterstrike::setupCamp: -> only camps may call this method. caller (" + getSelf() + " is not a camp.",
|
|
getSelf(), trace.TL_ERROR_LOG);
|
|
return;
|
|
}
|
|
|
|
if(registerLocs)
|
|
{
|
|
registerCampObjIds(campMaster);
|
|
}
|
|
|
|
erectShield();
|
|
spawnSurveillanceDroids(campMaster);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// checks the @outpostObject for a reference to the outpost master object
|
|
//
|
|
obj_id getMyOutpostId(obj_id outpostObject)
|
|
{
|
|
if(hasObjVar(outpostObject, OBJVAR_MY_CAMP_ID))
|
|
{
|
|
return getObjIdObjVar(outpostObject, OBJVAR_MY_CAMP_ID);
|
|
}
|
|
|
|
return null;
|
|
}
|