////////////////////////////////////////////// // 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; }