/** * Copyright (c)2000-2002 Sony Online Entertainment Inc. * All Rights Reserved * * Title: field.script * Description: script to be attached to factional mine fields * @author $Author:$ * @version $Revision:$ */ /***** INCLUDES ********************************************************/ include library.sui; include library.utils; include library.prose; include library.pclib; include library.combat; include library.ai_lib; include library.factions; include library.faction_perk; include library.player_structure; inherits systems.combat.combat_base_old; /***** CONSTANTS *******************************************************/ const string BLAST_PARTICLE_TEMPLATE = "object/static/particle/particle_sm_explosion.iff"; const string WARNING_PARTICLE_TEMPLATE = "object/static/particle/particle_mine_warning.iff"; //VOLUME HANDLING const string VOL_MINEFIELD = "volMineField"; const string HANDLER_MINEFIELD_TICK = "handleMinefieldTick"; const string HANDLER_MINEFIELD_EMPTY = "handleMinefieldEmpty"; const string VAR_EMPTY_BASE = "minefield.empty"; const string VAR_EMPTY_COUNT = "minefield.empty.count"; const string VAR_EMPTY_STAMP = "minefield.empty.stamp"; //PLAYER TRACKING const string SCRIPTVAR_MINEFIELD_NEAR = "minefield.near"; //PLAYER NOTIFICATION const string_id SID_MINEFIELD_NEAR = new string_id("faction_perk", "minefield_near"); const string_id SID_MINEFIELD_EXIT = new string_id("faction_perk", "minefield_exit"); const string_id SID_NO_MINES_TO_DONATE = new string_id("faction_perk", "no_mines_to_donate"); const string_id SID_NO_MINES_FROM_CRATE = new string_id("faction_perk", "no_mines_from_crate"); const string_id SID_NO_MINES_OUTSIDE_HQ = new string_id("faction_perk", "no_mines_outside_hq"); const string_id SID_TRAPPING_AVOID_MINE = new string_id("faction_perk", "trapping_avoid_mine"); const string_id SID_SUCCESS_LOCATE_MINE = new string_id("faction_perk", "success_locate_mine"); const string_id SID_CANNOT_DEFUSE_STATE = new string_id("faction_perk", "cannot_defuse_state"); const string_id SID_RECOVER_FUMBLED = new string_id("faction_perk", "recover_fumbled"); const string_id SID_SUCCESS_DISARM_MINE = new string_id("faction_perk", "success_disarm_mine"); const string_id SID_NO_LOCATE_MINE = new string_id("faction_perk", "no_locate_mine"); const string_id SID_NO_SUCCESS_DISARM = new string_id("faction_perk", "no_success_disarm"); const string_id SID_SUCCESSFULLY_DONATE = new string_id("faction_perk", "successfully_donate"); const string_id SID_UNSUCCESSFUL_DONATE = new string_id("faction_perk", "unsuccessful_donate"); const string_id SID_WISH_TO_DONATE = new string_id("faction_perk", "wish_to_donate"); const string_id SID_MINE_DONATION = new string_id("faction_perk", "mine_donation"); const string_id SID_MINE_COUNT = new string_id("faction_perk", "mine_count"); //CONTAINER HANDLING const string VAR_GOT = "container.got"; const string_id SID_ADD_ONLY_CONTAINER = new string_id("error_message", "add_only"); const string_id PROSE_WRONG_ITEM_TYPE = new string_id("error_message","wrong_item_type"); //MENUING const string_id SID_MINE_INV = new string_id("player_structure", "management_mine_inv"); const string_id SID_DEFUSE_MINE = new string_id("player_structure", "disarm_minefield"); const string_id SID_DONATE_MINES = new string_id("player_structure", "mnu_donate_mines"); //cleanup const string HANDLER_BLAST_CLEANUP = "handleBlastCleanup"; /***** TRIGGERS ********************************************************/ //TRIGGER VOLUME HANDLING trigger OnTriggerVolumeEntered(string volumeName, obj_id who) { if ( volumeName == VOL_MINEFIELD ) { int myFac = pvpGetAlignedFaction(self); int whoFac = pvpGetAlignedFaction(who); if ( pvpGetType( who )== PVPTYPE_NEUTRAL ) whoFac = 0; if ( pvpAreFactionsOpposed(myFac, whoFac) ) { notifyMinefieldNear(who); addMinefieldTarget(self, who); } } return SCRIPT_CONTINUE; } trigger OnTriggerVolumeExited(string volumeName, obj_id who) { if ( volumeName == VOL_MINEFIELD ) { int myFac = pvpGetAlignedFaction(self); int whoFac = pvpGetAlignedFaction(who); if ( pvpGetType( who )== PVPTYPE_NEUTRAL ) whoFac = 0; if ( pvpAreFactionsOpposed(myFac, whoFac) ) { notifyMinefieldExited(who); removeMinefieldTarget(self, who); } } return SCRIPT_CONTINUE; } //MENU HANDLING trigger OnObjectMenuRequest(obj_id player, menu_info mi) { if (!player_structure.isInstallation(self)) return SCRIPT_CONTINUE; int myFac = pvpGetAlignedFaction(self); int whoFac = pvpGetAlignedFaction(player); if ( pvpGetType( player )== PVPTYPE_NEUTRAL ) whoFac = 0; if ( myFac == whoFac ) { if ( hasObjVar(self, faction_perk.VAR_MINEFIELD_BASE) ) { if ( getOwner(self) == player && getGameObjectType(self) == GOT_installation_minefield ) mi.addRootMenu(menu_info_types.SERVER_HEAL_WOUND, SID_MINE_INV); else mi.addRootMenu(menu_info_types.SERVER_HEAL_WOUND_HEALTH, SID_DONATE_MINES); } } else if ( pvpAreFactionsOpposed(myFac, whoFac) ) { if ( hasObjVar(self, faction_perk.VAR_MINEFIELD_BASE) ) { mi.addRootMenu(menu_info_types.SERVER_HEAL_WOUND_ACTION, SID_DEFUSE_MINE); } } return SCRIPT_CONTINUE; } trigger OnObjectMenuSelect(obj_id player, int item) { if (!player_structure.isInstallation(self)) { return SCRIPT_CONTINUE; } int myFac = pvpGetAlignedFaction(self); int whoFac = pvpGetAlignedFaction(player); if ( pvpGetType( player )== PVPTYPE_NEUTRAL ) whoFac = 0; if ( item == menu_info_types.SERVER_HEAL_WOUND ) //mine inv { if ( hasObjVar(self, faction_perk.VAR_MINEFIELD_BASE) && (getContainerType(self) > 0) ) { if ( myFac == whoFac ) utils.requestContainerOpen(player, self); } } else if ( item == menu_info_types.SERVER_HEAL_WOUND_HEALTH ) //donate mines { if ( myFac == whoFac ) { string base_path = "donate." + player; if ( utils.hasScriptVar(self, base_path + ",pid") ) { int oldpid = utils.getIntScriptVar(self, base_path + ".pid"); sui.closeSUI(player, oldpid); utils.removeScriptVarTree(self, base_path); } obj_id[] mines = utils.getContainedGOTObjects(player, GOT_weapon_heavy_mine, true, false); if ( mines == null || mines.length == 0 ) { sendSystemMessage(player, SID_NO_MINES_TO_DONATE); return SCRIPT_CONTINUE; } resizeable string[] entries = new string[0]; for ( int i = 0; i < mines.length; i++ ) { obj_id container = getContainedBy(mines[i]); string containerName = getTemplateName(container); if (containerName != "object/factory/factory_crate_weapon.iff") { prose_package ppElement = prose.getPackage(SID_MINE_COUNT, mines[i], getCount(mines[i])); entries = utils.addElement(entries, " \0" + packOutOfBandProsePackage(null, ppElement)); } //entries = utils.addElement(entries, utils.getStringName(mines[i]) + " (" + getCount(mines[i]) + ")"); } if ( entries != null && entries.length > 0 ) { string prompt = utils.packStringId(SID_WISH_TO_DONATE); string title = utils.packStringId(SID_MINE_DONATION); int pid = sui.listbox(self, player, prompt, sui.OK_CANCEL, title, entries, "handleMineDonation"); if ( pid > -1 ) { utils.setScriptVar(self, base_path + ".pid", pid); utils.setScriptVar(self, base_path + ".mines", mines); return SCRIPT_CONTINUE; } } if (entries.length == 0) { sendSystemMessage(player, SID_NO_MINES_FROM_CRATE); return SCRIPT_CONTINUE; } } } else if ( item == menu_info_types.SERVER_HEAL_WOUND_ACTION ) //defuse mine { if ( hasObjVar(self, faction_perk.VAR_MINEFIELD_BASE) && (getContainerType(self) > 0) ) { if ( pvpAreFactionsOpposed(myFac, whoFac) ) { //LOG("minefield","OnObjectMenuSelect: queue'ing defuseMinefield..."); queueCommand(player, ##"defuseMinefield", self, "", COMMAND_PRIORITY_DEFAULT); } } } return SCRIPT_CONTINUE; } //CONTAINER HANDLING trigger OnAboutToOpenContainer(obj_id who) { if ( isPlayer(who) && (isGod(who) || getOwner(self) == who) ) { sendSystemMessage(who, SID_NO_MINES_OUTSIDE_HQ); return SCRIPT_OVERRIDE; } return SCRIPT_OVERRIDE; } trigger OnAboutToLoseItem(obj_id srcContainer, obj_id transferer, obj_id item) { if ( isPlayer(transferer) && (getOwner(self) != transferer) ) { sendSystemMessage(transferer, SID_ADD_ONLY_CONTAINER); return SCRIPT_OVERRIDE; } return SCRIPT_CONTINUE; } trigger OnAboutToReceiveItem(obj_id srcContainer, obj_id transferer, obj_id item) { if ( isPlayer(transferer) && (pvpGetAlignedFaction(self) == pvpGetAlignedFaction(transferer)) && (pvpGetType( transferer ) != PVPTYPE_NEUTRAL) ) { int got = getGameObjectType(item); if ( got != GOT_weapon_heavy_mine ) { string_id got_sid = getGameObjectTypeStringId(got); prose_package pp = prose.getPackage(PROSE_WRONG_ITEM_TYPE, self, got_sid); sendSystemMessageProse(transferer, pp); return SCRIPT_OVERRIDE; } if ( !factions.isDeclared(transferer) ) pvpHelpPerformed(transferer, self); } return SCRIPT_CONTINUE; } trigger OnLostItem(obj_id destContainer, obj_id transferer, obj_id item) { obj_id[] contents = getContents(self); if ( (contents == null) || (contents.length == 0) ) setMinefieldEmpty(self); return SCRIPT_CONTINUE; } trigger OnReceivedItem(obj_id srcContainer, obj_id transferer, obj_id item) { if ( hasObjVar(self, VAR_EMPTY_BASE) ) removeObjVar(self, VAR_EMPTY_BASE); return SCRIPT_CONTINUE; } //INITIALIZATION trigger OnAttach() { updateMinefieldExtents(); return SCRIPT_CONTINUE; } trigger OnDetach() { return SCRIPT_CONTINUE; } trigger OnInitialize() { if(!hasScript(self, "faction_perk.hq.defense_object")) { obj_id[] contents = getContents(self); if ( (contents == null) || (contents.length == 0) ) { player_structure.destroyStructure(self, false); return SCRIPT_CONTINUE; } } if ( !hasObjVar(self, "pvpCanAttack") ) setObjVar(self, "pvpCanAttack", 1); createMinefieldVolume(); return SCRIPT_CONTINUE; } /***** MESSAGEHANDLERS *************************************************/ messageHandler handleMinefieldTick() { ////LOG("minefield","handleMinefieldTick(" + self + "): entered..."); obj_id[] targets = utils.getObjIdBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS); location[] locs = utils.getLocationBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS); if ( (targets == null) || (targets.length == 0) || (locs == null) || (locs.length == 0) ) { ////LOG("minefield","handleMinefieldTick(" + self + "): no/invalid target arrays..."); return SCRIPT_CONTINUE; } if ( targets.length != locs.length ) { ////LOG("minefield","handleMinefieldTick(" + self + "): re-sync'ing arrays"); removeMinefieldVolume(); createMinefieldVolume(); return SCRIPT_CONTINUE; } ////LOG("minefield","handleMinefieldTick(" + self + "): gathering extents..."); float minX = getFloatObjVar(self, faction_perk.VAR_MINEFIELD_MIN_X); float minZ = getFloatObjVar(self, faction_perk.VAR_MINEFIELD_MIN_Z); float maxX = getFloatObjVar(self, faction_perk.VAR_MINEFIELD_MAX_X); float maxZ = getFloatObjVar(self, faction_perk.VAR_MINEFIELD_MAX_Z); boolean noMines = false; resizeable obj_id[] toRemove = new obj_id[0]; for ( int i = 0; i < targets.length; i++ ) { if ( !isPlayer(targets[i]) && ai_lib.isDead(targets[i]) ) { toRemove = utils.addElement(toRemove, targets[i]); } else { location spot = getLocation(targets[i]); if (spot != null) { if(!noMines) //if ( isInMinefield(spot, minX, minZ, maxX, maxZ) && !noMines ) { float dist = getDistance(locs[i], spot); int chance = (int)(dist * faction_perk.CHANCE_PER_METER); int roll = rand(0, 100); ////LOG("minefield","handleMinefieldTick(" + self + "): target: " + targets[i] + " chance = " + chance + " roll = " + roll); if ( roll < chance ) { /*if ( isPlayer(targets[i]) ) sendSystemMessageTestingOnly(targets[i], "You would have detonated a mine :P");*/ ////LOG("minefield","handleMinefieldTick(" + self + "): attempting to detonate mine against " + targets[i]); if ( !detonateMine(self, targets[i]) ) { noMines = true; } } } locs[i] = spot; } } } if (locs != null && locs.length > 0) utils.setBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS, locs); if ( (toRemove != null) && (toRemove.length > 0) ) { for ( int i = 0; i < toRemove.length; i++ ) { removeMinefieldTarget(self, toRemove[i]); } } messageTo(self, HANDLER_MINEFIELD_TICK, null, faction_perk.BASE_MINEFIELD_TICK, false); return SCRIPT_CONTINUE; } messageHandler handleBlastCleanup() { if ( params == null || params.isEmpty() ) return SCRIPT_CONTINUE; obj_id blast = params.getObjId("blastId"); if ( isIdValid(blast) ) destroyObject(blast); return SCRIPT_CONTINUE; } messageHandler handleMinefieldEmpty() { if ( !hasObjVar(self, VAR_EMPTY_BASE) ) return SCRIPT_CONTINUE; obj_id[] contents = getContents(self); if ( (contents != null) || (contents.length > 0) ) { removeObjVar(self, VAR_EMPTY_BASE); return SCRIPT_CONTINUE; } int cnt = getIntObjVar(self, VAR_EMPTY_COUNT); int stamp = getIntObjVar(self, VAR_EMPTY_STAMP); int now = getGameTime(); if ( now >= (stamp + 360) ) { cnt++; if ( cnt > 25 ) { //destroyObject(self); player_structure.destroyStructure(self, false); return SCRIPT_CONTINUE; } setObjVar(self, VAR_EMPTY_COUNT, cnt); setObjVar(self, VAR_EMPTY_STAMP, now); messageTo(self, HANDLER_MINEFIELD_EMPTY, null, 360, true); } return SCRIPT_CONTINUE; } messageHandler handleMineDonation() { obj_id player = sui.getPlayerId(params); if ( !isIdValid(player) ) return SCRIPT_CONTINUE; string base_path = "donate." + player; if ( !utils.hasScriptVar(self, base_path + ".pid") ) return SCRIPT_CONTINUE; obj_id[] mines = utils.getObjIdArrayScriptVar(self, base_path + ".mines"); utils.removeScriptVarTree(self, base_path); if ( mines == null || mines.length == 0 ) return SCRIPT_CONTINUE; int bp = sui.getIntButtonPressed(params); if ( bp == sui.BP_CANCEL ) return SCRIPT_CONTINUE; int idx = sui.getListboxSelectedRow(params); if ( idx < 0 ) return SCRIPT_CONTINUE; if ( idx >= mines.length ) return SCRIPT_CONTINUE; if ( putIn(mines[idx], self) ) { prose_package ppSuccess = prose.getPackage(SID_SUCCESSFULLY_DONATE, self, mines[idx]); sendSystemMessageProse(player, ppSuccess); } else { prose_package ppUnsuccess = prose.getPackage(SID_UNSUCCESSFUL_DONATE, self, mines[idx]); sendSystemMessageProse(player, ppUnsuccess); } return SCRIPT_CONTINUE; } /***** FUNCTIONS *******************************************************/ boolean addMinefieldTarget(obj_id self, obj_id target) { if ( !isIdValid(target) || !isIdValid(self) ) return false; resizeable obj_id[] targets = utils.getResizeableObjIdBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS); resizeable location[] locs = utils.getResizeableLocationBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS); if ( (targets == null) || (targets.length == 0) || (locs == null) || (locs.length == 0) ) { targets = null; locs = null; messageTo(self, HANDLER_MINEFIELD_TICK, null, faction_perk.BASE_MINEFIELD_TICK, false); } targets = utils.addElement(targets, target); location target_loc = getLocation(target); if (target_loc != null) locs = utils.addElement(locs, target_loc); else return false; if ( (targets == null) || (targets.length == 0) || (locs == null) || (locs.length == 0) ) return false; utils.setBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS, targets); utils.setBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS, locs); return true; } boolean removeMinefieldTarget(obj_id self, obj_id target) { if ( !isIdValid(target) || !isIdValid(self) ) return false; resizeable obj_id[] targets = utils.getResizeableObjIdBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS); resizeable location[] locs = utils.getResizeableLocationBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS); if ( (targets == null) || (targets.length == 0) || (locs == null) || (locs.length == 0) ) return false; int idx = utils.getElementPositionInArray(targets, target); if ( idx < 0 ) return false; targets = utils.removeElementAt(targets, idx); locs = utils.removeElementAt(locs, idx); if ( (targets == null) || (targets.length == 0) || (locs == null) || (locs.length == 0) ) { utils.removeBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS); utils.removeBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS); } else { utils.setBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS, targets); utils.setBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS, locs); } return true; } boolean createMinefieldVolume() { obj_id self = getSelf(); if ( !isIdValid(self) ) return false; int size = 1; if ( hasObjVar(self, faction_perk.VAR_MINEFIELD_SIZE) ) { size = getIntObjVar(self, faction_perk.VAR_MINEFIELD_SIZE); CustomerServiceLog("minefields", "Minefield:" + "(" + self + ")" + " has a radius of " + size); } if ( size < 1 ) return false; float range = (float)size * 8f * 1.5f; //size * lotSize * justOverRoot2 createTriggerVolume(VOL_MINEFIELD, range, true); return true; } void removeMinefieldVolume() { obj_id self = getSelf(); if ( !isIdValid(self) ) return; removeTriggerVolume(VOL_MINEFIELD); } void notifyMinefieldNear(obj_id target) { if ( !isIdValid(target) || !isPlayer(target) ) return; int cnt = utils.getIntScriptVar(target, SCRIPTVAR_MINEFIELD_NEAR); if ( cnt == 0 ) { sendSystemMessage(target, SID_MINEFIELD_NEAR); } cnt++; utils.setScriptVar(target, SCRIPTVAR_MINEFIELD_NEAR, cnt); } void notifyMinefieldExited(obj_id target) { if ( !isIdValid(target) ) return; int cnt = utils.getIntScriptVar(target, SCRIPTVAR_MINEFIELD_NEAR); cnt--; if ( cnt < 1 ) { sendSystemMessage(target, SID_MINEFIELD_EXIT); utils.removeScriptVar(target, SCRIPTVAR_MINEFIELD_NEAR); return; } utils.setScriptVar(target, SCRIPTVAR_MINEFIELD_NEAR, cnt); } void explodeMine(obj_id minefield, obj_id mine, obj_id target, location detonation) { if ( !isIdValid(minefield) || !isIdValid(mine) || !isIdValid(target) ) return; int fieldFac = pvpGetAlignedFaction(minefield); /*obj_id blast = createObject(BLAST_PARTICLE_TEMPLATE, detonation); if ( isIdValid(blast) ) { dictionary cleanup = new dictionary(); cleanup.put("blastId", blast); messageTo(minefield, HANDLER_BLAST_CLEANUP, cleanup, 5, false); }*/ float damageRadius = faction_perk.MINE_DAMAGE_RADIUS; resizeable obj_id[] combatTargets = new obj_id[0]; obj_id[] creatures = getCreaturesInRange(detonation, damageRadius); if ( (creatures != null) && (creatures.length > 0) ) { for ( int i = 0; i < creatures.length; i++ ) { int cFac = pvpGetAlignedFaction(creatures[i]); if ( pvpGetType( creatures[i] )== PVPTYPE_NEUTRAL ) cFac = 0; if ( pvpAreFactionsOpposed(fieldFac, cFac) ) { if ( isPlayer(creatures[i]) && getPosture(creatures[i]) == POSTURE_INCAPACITATED ) { pclib.coupDeGrace(creatures[i], minefield); } else { pvpSetFactionEnemyFlag(creatures[i], fieldFac); combatTargets = utils.addElement(combatTargets, creatures[i]); /* location cLoc = getLocation(creatures[i]); float dist = getDistance(detonation, cLoc); */ //modify damage based on distance //apply damage } } } } location fieldLoc = getLocation(minefield); location tarLoc = getLocation(target); obj_id[] targets = utils.toStaticObjIdArray(combatTargets); doMineDamage(minefield, mine, target, targets); CustomerServiceLog("minefields", "Minefield:" + "(" + minefield + ")" + " is located at " + fieldLoc + " and exploded on " + target + " at location " + tarLoc); if ( rand(0,100) < 5 ) { //chain reaction! obj_id[] possibleTargets = utils.getObjIdBatchScriptVar(minefield, faction_perk.VAR_MINEFIELD_TARGET_IDS); int nextIdx = rand(0, possibleTargets.length - 1); obj_id nextTarget = possibleTargets[nextIdx]; if ( isIdValid(nextTarget) ) { CustomerServiceLog("minefields", "Minefield:" + "(" + minefield + ")" + " is located at " + fieldLoc + " and exploded on " + target + " at location " + tarLoc); detonateMine(minefield, nextTarget); } } } obj_id getRandomMine(obj_id minefield) { if ( !isIdValid(minefield) ) return null; obj_id[] mines = utils.getContainedGOTObjects(minefield, GOT_weapon_heavy_mine, true, false); if ( mines != null && mines.length > 0 ) { int idx = rand(0, mines.length - 1); return mines[idx]; } setMinefieldEmpty(minefield); return null; } boolean detonateMine(obj_id minefield, obj_id target) { if ( !isIdValid(minefield) || !isIdValid(target) ) return false; int mFac = pvpGetAlignedFaction(minefield); int tFac = pvpGetAlignedFaction(target); if ( pvpGetType( target ) == PVPTYPE_NEUTRAL ) tFac = 0; if ( !pvpAreFactionsOpposed(mFac, tFac) ) { removeMinefieldTarget(minefield, target); return false; } obj_id mine = getRandomMine(minefield); if ( isIdValid(mine) ) { /*if ( isPlayer(target) ) sendSystemMessageTestingOnly(target, "Attempting to detonate a mine with you as the target..."); }*/ location fieldLoc = getLocation(minefield); location tarLoc = getLocation(target); float range = rand(0f, 0.75f); location loc = utils.getRandomLocationInRing(getLocation(target), 0f, 0.75f); explodeMine(minefield, mine, target, loc); CustomerServiceLog("minefields", "Minefield:" + "(" + minefield + ")" + " is located at " + fieldLoc + " and exploded on " + target + " at location " + tarLoc); return true; } return false; } location getRandomLocationInMinefield(obj_id minefield) { if ( !isIdValid(minefield) ) return null; location fieldLoc = getLocation(minefield); float minX = getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MIN_X); float minZ = getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MIN_Z); float maxX = getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MAX_X); float maxZ = getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MAX_Z); float x = rand(minX, maxX); float z = rand(minZ, maxZ); return new location(x, fieldLoc.y, z); } void setMinefieldEmpty(obj_id minefield) { if ( !isIdValid(minefield) ) return; if ( !hasObjVar(minefield, VAR_EMPTY_BASE) ) { setObjVar(minefield, VAR_EMPTY_COUNT, 1); setObjVar(minefield, VAR_EMPTY_STAMP, getGameTime()); messageTo(minefield, HANDLER_MINEFIELD_EMPTY, null, 360, true); } } void updateMinefieldExtents() { obj_id self = getSelf(); int size = getIntObjVar(self, faction_perk.VAR_MINEFIELD_SIZE); if ( size < 1 ) return; location here = getLocation(self); setObjVar(self, faction_perk.VAR_MINEFIELD_MIN_X, here.x - 4f); setObjVar(self, faction_perk.VAR_MINEFIELD_MIN_Z, here.z - 4f); setObjVar(self, faction_perk.VAR_MINEFIELD_MAX_X, here.x + 4f); setObjVar(self, faction_perk.VAR_MINEFIELD_MAX_Z, here.z + 4f); } boolean isInMinefield(location here, float minx, float minz, float maxx, float maxz) { if ( here == null ) return false; boolean inX = false; boolean inZ = false; if ( here.x >= minx && here.x <= maxx ) inX = true; if ( here.z >= minz && here.z <= maxz ) inZ = true; return (inX && inZ); } boolean isInMinefield(obj_id target, obj_id minefield) { if ( !isIdValid(target) || !isIdValid(minefield) ) return false; if ( !exists(target) || !target.isLoaded() ) return false; if ( !hasObjVar(minefield, faction_perk.VAR_MINEFIELD_EXTENTS_BASE) ) return false; location here = getLocation(target); if ( here == null ) return false; location mineLoc = getLocation( minefield ); float minX = mineLoc.x + getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MIN_X); float minZ = mineLoc.z + getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MIN_Z); float maxX = mineLoc.x + getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MAX_X); float maxZ = mineLoc.z + getFloatObjVar(minefield, faction_perk.VAR_MINEFIELD_MAX_Z); return isInMinefield(here, minX, minZ, maxX, maxZ); } void doMineDamage(obj_id minefield, obj_id mine, obj_id target, obj_id[] combatTargets) { ////LOG("minefield","*** doMineDamage: entered..."); if ( !isIdValid(minefield) || !isIdValid(mine) || !isIdValid(target) ) { ////LOG("minefield","doMineDamage: invalid params!!"); return; } // Data needed per attack const string ANIMATION_ACTION = ""; const float DAMAGE_MODIFIER = 1.0f; // modifier for damage from basic attack // attrib cost mods const float HEALTH_COST_MODIFIER = 0.0f; const float ACTION_COST_MODIFIER = 0.0f; const int BASE_TO_HIT_MODIFIER = 75; // how far off of 75 do we want the base to hit roll const float AMMO_COST_MODIFIER = 1.0f; // modifier for ammo cost string[] strTimeMods = {}; string[] strDamageMods = {}; string[] strCostMods = {}; string[] strToHitMods= {}; string[] strBlockMods = {}; string[] strEvadeMods = {}; string[] strCounterAttackMods = {}; // special response information int intBlockMod = 1000; //The larger number makes it more difficult to block int intEvadeMod = 1000; //The larger number makes it more difficult to evade int intCounterAttackMod = 1000; //The larger number makes it more difficult to counter int intAttackerEndPosture = POSTURE_NONE; //int intDefenderEndPosture = POSTURE_KNOCKED_DOWN; int intDefenderEndPosture = POSTURE_NONE; // change to above to make knock down // below are 2 matched arrays Don't let them get out of synch int[] intEffects = {}; // const int's defined in base_class float[] fltEffectDurations = {}; int intChanceToApplyEffect= 0; // 1-100 rating for whether we apply a state int intToHitMod = 0; // we're going to need to append the weapon type to these i think,.. // here is hack instead // where do we get Attack range? float fltAttackRange = 5; float fltRadius = getWeaponDamageRadius(mine); //obj_id[] objDefenders = pvpGetEnemiesInRange(self, target, fltRadius); // FIX THIS LATER obj_id[] objDefenders = combatTargets; if(objDefenders==null || objDefenders.length<1) { objDefenders = new obj_id[1]; objDefenders[0] = target; } objDefenders = truncateTargetArray(objDefenders, target, MAX_TARGET_ARRAY_SIZE); objDefenders = validateDefenders(minefield, objDefenders); if(objDefenders.length<1) { return; } attacker_data cbtAttackerData = new attacker_data(); weapon_data cbtWeaponData = new weapon_data(); defender_data[] cbtDefenderData = new defender_data[objDefenders.length]; // ALWAYS AN ARRAY DO NOT EVER CHANGE DO NOT NEVER! if (!getCombatData(minefield, objDefenders, cbtAttackerData, cbtDefenderData, cbtWeaponData)) { LOG("Combat", "WARNING: field.doMineDamage call to getCombatData returned false"); return; } // begin giant hack! cbtWeaponData = getWeaponData(mine); if(cbtWeaponData==null) { ////LOG("minefield","doMineDamage: cbtWeaponData is returning from getWeaponData() as null"); } // This line was removed because the method getWeaponStringType() is not defined anywhere, and the variable strWeaponType is not used // at any other place. The line appears to be useless... much like minefields. // // string strWeaponType = getWeaponStringType(cbtWeaponData.weaponType); //cbtWeaponData = getRawDamage(mine, cbtWeaponData, DAMAGE_MODIFIER, strDamageMods); // now we need to set all of the information for cbtAttackerData; cbtAttackerData.weaponSkillMod = 1000000; dictionary dctParams = new dictionary(); ////////LOG("combat_grenade", "deleting grenade!"); messageTo(mine, "grenadeUsed", dctParams, 0, true); hit_result[] cbtHitData = runHitEngine(cbtAttackerData, cbtWeaponData, cbtDefenderData); // gives us our hit/miss things if(cbtHitData==null) { ////LOG("minefield","doMineDamage: cbtHitData is returning from runHitEngine() as null"); return; } ////LOG("combat_grenade","Got hit engine results!"); attacker_results cbtAttackerResults = new attacker_results(); // blank data for attacker information cbtAttackerResults.id = mine; // MUST DO THIS! defender_results[] cbtDefenderResults = createDefenderResultsArray(cbtHitData.length); // defender information // pass by reference below, so be careful ////LOG("combat_grenade","Setting Combat Results!"); setDefenderCombatResults(cbtWeaponData, cbtAttackerData, cbtAttackerResults, cbtHitData, cbtDefenderData, cbtDefenderResults, strBlockMods, intBlockMod, strEvadeMods, intEvadeMod, strCounterAttackMods, intCounterAttackMod, false); // sorry this function sucks so much ////LOG("combat_grenade","Applying Postures!"); applyPostures(cbtAttackerData, cbtAttackerResults, cbtHitData, cbtDefenderData, cbtDefenderResults, intAttackerEndPosture, intDefenderEndPosture, cbtWeaponData); //int[] intEffectToApply = new int[1]; //intEffectToApply[0] = intEffects[rand(0,intEffects.length-1)]; int[] intEffectToApply = new int[1]; finalizeMineDamage(cbtAttackerData.id, cbtWeaponData, cbtDefenderData, cbtHitData, cbtDefenderResults); // applies all of the necessary damage doMineFieldResults("clienteffect/combat_explosion_lair_large.cef",cbtAttackerResults, cbtDefenderResults, cbtHitData, target, cbtWeaponData); } commandHandler cmdDefuseMinefield() { //LOG("minefield","cmdDefuseMinefield: entered..."); //LOG("minefield","cmdDefuseMinefield: self = " + self + " target = " + target + " params = " + params); if ( !isIdValid(target) ) return SCRIPT_CONTINUE; int mFac = pvpGetAlignedFaction(self); int tFac = pvpGetAlignedFaction(target); if ( pvpGetType( target ) == PVPTYPE_NEUTRAL ) tFac = 0; if ( !pvpAreFactionsOpposed(mFac, tFac) ) return SCRIPT_CONTINUE; if ( !isInMinefield(target, self) ) { //LOG("minefield","cmdDefuseMinefield: target not in minefield..."); defuseLocateMineFail(target); return SCRIPT_CONTINUE; } obj_id mine = getRandomMine(self); if ( !isIdValid(mine) ) { //LOG("minefield","cmdDefuseMinefield: no mines to locate!"); defuseLocateMineFail(target); return SCRIPT_CONTINUE; } obj_id[] targets = utils.getObjIdBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_IDS); location[] locs = utils.getLocationBatchScriptVar(self, faction_perk.VAR_MINEFIELD_TARGET_LOCS); if ( (targets == null) || (targets.length == 0) || (locs == null) || (locs.length == 0) ) { //LOG("minefield","cmdDefuseMinefield: invalid targets list!!"); defuseLocateMineFail(target); return SCRIPT_CONTINUE; } int idx = utils.getElementPositionInArray(targets, target); if ( idx < 0 ) { defuseLocateMineFail(target); return SCRIPT_CONTINUE; } if ( !factions.isDeclared(target) ) pvpSetFactionEnemyFlag(target, mFac); location here = getLocation(target); location there = locs[idx]; float travel = getDistance(here, there); location minefield = getLocation(self); float range = getDistance(here, minefield); float magicRatio = 3f/2f; int chance = (int)(travel * faction_perk.CHANCE_PER_METER * magicRatio) + 10 - (int)range; int roll = rand(0, 100); //LOG("minefield","cmdDefuseMinefield: locate chance = " + chance + " roll = " + roll); float delay = 5f; boolean locatedMine = false; if ( roll == 100 ) { locatedMine = true; } else if ( roll < 10 ) //step on mine? { int trapping = getSkillStatMod(target, "trapping"); //avoid detonation after bad locate if ( trapping > 0 ) { int avoidBadLocate = rand(0, 100); if ( avoidBadLocate < trapping/2 ) { //LOG("minefield","cmdDefuseMinefield: avoided bad locate!"); sendSystemMessage(target, SID_TRAPPING_AVOID_MINE); delay += 1f; locatedMine = true; } } if ( !locatedMine ) { detonateMine(self, target); return SCRIPT_CONTINUE; } } else { if ( roll < chance ) { locatedMine = true; } } int locomotion = getLocomotion(target); if ( !locatedMine ) { //LOG("minefield","cmdDefuseMinefield: locate failed!"); defuseLocateMineFail(target); return SCRIPT_CONTINUE; } else { //LOG("minefield","cmdDefuseMinefield: mine located!"); sendSystemMessage(target, SID_SUCCESS_LOCATE_MINE); if ( locomotion != LOCOMOTION_KNEELING ) queueCommand(target, ##"kneel", null, "", COMMAND_PRIORITY_DEFAULT); } dictionary defuseData = new dictionary(); defuseData.put("target", target); defuseData.put("mine", mine); messageTo(self, "handleMineDefuse", defuseData, delay, false); return SCRIPT_CONTINUE; } commandHandler cmdDefuseMinefieldFail() { if ( !isIdValid(target) ) return SCRIPT_CONTINUE; sendSystemMessage(target, SID_CANNOT_DEFUSE_STATE); return SCRIPT_CONTINUE; } messageHandler handleMineDefuse() { //LOG("minefield","handleMineDefuse: entering..."); if ( params == null || params.isEmpty() ) return SCRIPT_CONTINUE; obj_id target = params.getObjId("target"); obj_id mine = params.getObjId("mine"); if ( !isIdValid(target) || !isIdValid(mine) ) return SCRIPT_CONTINUE; int generalAssembly = getSkillStatMod(target, "general_assembly"); //dismantle base int roll = rand(0, 100); boolean defusedMine = false; if ( roll == 100 ) { defusedMine = true; } else if ( roll < 10 ) //fumble dismantle? { int grenadeAssembly = getSkillStatMod(target, "grenade_assembly"); //avoid detonation after bad dismantle if ( grenadeAssembly > 0 ) { int avoidBadDismantle = rand(0, 100); if ( avoidBadDismantle < grenadeAssembly ) { sendSystemMessage(target, SID_RECOVER_FUMBLED); defusedMine = true; } } if ( !defusedMine ) { defuseMineFail(self, target); return SCRIPT_CONTINUE; } } else { if ( roll < generalAssembly ) { defusedMine = true; } } if ( !defusedMine ) { defuseMineFail(self, target); } else { //LOG("minefield","cmdDefuseMinefield: mine defused!"); sendSystemMessage(target, SID_SUCCESS_DISARM_MINE); messageTo(mine, "grenadeUsed", null, 0, true); } queueCommand(target, ##"stand", null, "", COMMAND_PRIORITY_DEFAULT); //LOG("minefield","cmdDefuseMinefield: default exit..."); return SCRIPT_CONTINUE; } void defuseLocateMineFail(obj_id target) { sendSystemMessage(target, SID_NO_LOCATE_MINE); } void defuseMineFail(obj_id minefield, obj_id target) { sendSystemMessage(target, SID_NO_SUCCESS_DISARM); detonateMine(minefield, target); }