/********************************************************************** * Copyright (c)2008 Sony Online Entertainment Inc. * All Rights Reserved * **********************************************************************/ /***** INCLUDES ********************************************************/ include library.combat; include library.space_utils; include library.sui; include library.utils; include java.util.Enumeration; /***** LOGGING *******************************************************/ const string TERMINAL_LOGGING = "target_creature"; const boolean LOGGING_ON = true; /***** CONSTANTS *******************************************************/ const string OWNER_OBJVAR = "targetDummyOwner"; const string CREATURE_NAME_OBJVAR = "targetDummyCreatureName"; const string TARGET_DUMMY_CONTROLLER_OBJVAR = "targetDummyController"; const string TARGET_DUMMY_ID_OBJVAR = "targetDummyId"; const string TARGET_DUMMY_SOUND_DELAY = "targetDummySoundDelay"; const string TARGET_DUMMY_NO_SOUND = "targetDummyNoSound"; const string[] TARGET_DUMMY_DEFENSES = { "expertise_innate_protection_all", "expertise_dodge", "expertise_parry", "expertise_block_chance", "expertise_glancing_blow_all", "expertise_evasion_chance" }; const string BASE_TARGET_DUMMY_VAR = "target_dummy"; const string ALL_ATTACKS_SUB_VAR = "all_attacks"; const string LAST_ATTACK_TIME_VAR = "lastAttackTime"; const int PURGE_DATA_INTERVAL = 6*60*60; // hours x minutes per hour x seconds per minute const int INDEX_NUM_OF_ATTACKS = 0; const int INDEX_TOTAL_DAMAGE_DONE = 1; const int INDEX_LARGEST_ATTACK = 2; const int INDEX_SMALLEST_ATTACK = 3; const int INDEX_NUM_CRITAL_HITS = 4; const int INDEX_NUM_STRIKETHROUGH = 5; const int INDEX_NUM_MISSED = 6; const int INDEX_NUM_DODGED = 7; const int INDEX_NUM_PARRIED = 8; const int INDEX_NUM_GLANCING_HITS = 9; const int INDEX_NUM_EVADED_HITS = 10; const int INDEX_NUM_BLOCKED_HITS = 11; const int INDEX_NUM_SUCCESSFUL_HITS = 12; const int INDEX_NUM_NORMAL_HITS = 13; const string[] ATTACK_DATA_ARRAY = { "numAttacks", "totalDamageDone", "largestAttack", "smallestAttack", "numCriticalHits", "numStrikethroughHit", "numMissed", "numDodged", "numParried", "numGlancingHit", "numEvadedHit", "numBlockedHit", "numSuccessfulAttacks", "numNormalHits" }; // For output sui const string_id REPORT_TITLE_SID = new string_id("target_dummy", "report_title"); const string_id REPORT_ATTACK_TYPE_SID = new string_id("target_dummy", "report_attack_type"); const string_id REPORT_NUM_ATTACKS_SID = new string_id("target_dummy", "report_num_attacks"); const string_id REPORT_TOTAL_DAMAGE_SID = new string_id("target_dummy", "report_total_damage"); const string_id REPORT_AVERAGE_DAMAGE_SID = new string_id("target_dummy", "report_average_damage"); const string_id REPORT_SMALLEST_ATTACK_SID = new string_id("target_dummy", "report_smallest_attack"); const string_id REPORT_LARGEST_ATTACK_SID = new string_id("target_dummy", "report_largest_attack"); const string_id REPORT_NUM_CRITS_SID = new string_id("target_dummy", "report_num_crits"); const string_id REPORT_NUM_STRIKETHROUGH_SID = new string_id("target_dummy", "report_num_strikethrough"); const string_id REPORT_NUM_MISSES_SID = new string_id("target_dummy", "report_num_misses"); const string_id REPORT_NUM_DODGES_SID = new string_id("target_dummy", "report_num_dodges"); const string_id REPORT_NUM_PARRIES_SID = new string_id("target_dummy", "report_num_parries"); const string_id REPORT_NUM_GLANCING_SID = new string_id("target_dummy", "report_num_glancing"); const string_id REPORT_NUM_EVADES_SID = new string_id("target_dummy", "report_num_evades"); const string_id REPORT_NUM_BLOCKED_SID = new string_id("target_dummy", "report_num_blocked"); const string_id REPORT_NUM_SUCCESSFUL_SID = new string_id("target_dummy", "report_num_successful_attacks"); const string_id REPORT_NUM_NORMAL_SID = new string_id("target_dummy", "report_num_normal_hits"); const string_id SID_TARGET_DUMMY_DIED_RESSURECTION = new string_id("target_dummy", "target_died_ressurected"); const string_id REPORT_LINE_BREAK_SID = new string_id("target_dummy", "report_line_break"); const string_id SID_SOUND_ANIMS_ON = new string_id("target_dummy", "sounds_anims_on"); const string_id SID_SOUND_ANIMS_OFF = new string_id("target_dummy", "sounds_anims_off"); const string_id REPORT_PERCENT_SIGN = new string_id("target_dummy", "report_percent"); const string GREEN = " \\#99FF33 "; const string RED = " \\#FF3300 "; const string ORANGE = " \\#FF8C00 "; const string WHITE = " \\#FFFFFF "; const string BLUE = " \\#0099FF "; const string YELLOW = " \\#FFFF00 "; const string LINE = " \n "; //Target Dummy Animations const string[] TARGET_DUMMY_ANIMS = { "shiver", "shake_head_no", "slump_head", "beg", "apologize", "cover_eyes", "cover_mouth", "hands_above_head", "hug_self", "implore" }; string addLineBreaks(int num) { string lineBreaks = ""; for(int i = 1; i <= num; i++) { lineBreaks += LINE; } return lineBreaks; } string percentSign() { return " "+utils.packStringId(REPORT_PERCENT_SIGN); } /***** FUNCTIONS *******************************************************/ boolean isTargetDummy(obj_id target) { return hasObjVar(target, "isTargetDummy"); } // Called from OnObjectMenuSelect, so we validate the location. obj_id createTargetDummy(obj_id controller, obj_id player) { if(!isValidId(controller) || !isValidId(player)) return obj_id.NULL_ID; string creature = getTargetDummyCreatureType(controller); if(creature == null || creature.equals("")) return obj_id.NULL_ID; if(creature.equals("tcg_target_dummy")) { if(isInWorldCell(player) || isInWorldCell(controller)) { blog("Both are in world cell, abort"); return obj_id.NULL_ID; } location controllerLocation = getLocation(controller); location awayLoc = utils.getRandomAwayLocation(controllerLocation, 1.f, 2.f); if((awayLoc.cell != null) || isIdValid(awayLoc.cell)) awayLoc = controllerLocation; if(!permittedToCallTargetDummy(player, awayLoc)) return obj_id.NULL_ID; obj_id creatureObject = createTargetDummyAtLocation(controller, player, awayLoc); messageTo(creatureObject, "faceThePlayer", null, 2, false); messageTo(creatureObject, "checkCurrentLocation", null, 1, false); return creatureObject; } else { location where = getLocation(controller); if(!permittedToCallTargetDummy(player, where)) return obj_id.NULL_ID; return createTargetDummyAtLocation(controller, player, where); } } // Called from OnInitialize trigger. // The Location should be legal based on check when player originally placed the controller. obj_id recreateTargetDummy(obj_id controller, obj_id player) { if(isInWorldCell(controller)) return obj_id.NULL_ID; location where = getLocation(controller); obj_id targetDummyObj = createTargetDummyAtLocation(controller, player, where); if(getTargetDummyCreatureType(controller).equals("tcg_target_dummy")) { float controllerYaw = getYaw(controller); location offsetLoc = where; offsetLoc.x += 2f; location pathToLoc = utils.rotatePointXZ(where, offsetLoc, controllerYaw); pathTo(targetDummyObj, pathToLoc); setYaw(targetDummyObj, controllerYaw); messageTo(targetDummyObj, "checkCurrentLocation", null, 1, false); } return targetDummyObj; } obj_id createTargetDummyAtLocation(obj_id controller, obj_id player, location createLoc) { obj_id npc = obj_id.NULL_ID; obj_id owner = getTargetDummyOwnerFromController(controller); if ( isIdValid(owner) ) { string toCreate = getTargetDummyCreatureType(controller); npc = create.object(toCreate, createLoc); if ( isIdValid(npc) ) { float controllerYaw = getYaw(controller); if ( exists(player) ) { location playerLoc = getLocation(player); if ( playerLoc.cell == createLoc.cell ) { faceTo(npc, player); } else { setYaw(npc, controllerYaw); } } else { setYaw(npc, controllerYaw); } obj_id structure = getTopMostContainer(controller); if ( isIdValid(structure) && isGameObjectTypeOf(structure, GOT_building_player) ) { permissionsAddAllowed(structure, npc.toString()); } setObjVar(npc, OWNER_OBJVAR, owner); setObjVar(npc, TARGET_DUMMY_CONTROLLER_OBJVAR, controller); setObjVar(controller, TARGET_DUMMY_ID_OBJVAR, npc); ai_lib.setDefaultCalmBehavior(npc, ai_lib.BEHAVIOR_SENTINEL); string planet = createLoc.area; if( planet.startsWith("space_") ) { setInvulnerable(npc, true); } } } return npc; } void cleanupTargetDummy(obj_id controller, obj_id targetDummy) { removeObjVar(controller, target_dummy.TARGET_DUMMY_ID_OBJVAR); removeTargetDummyFromPermissions(targetDummy); destroyObject(targetDummy); return; } void removeTargetDummyFromPermissions(obj_id targetDummy) { obj_id structure = getTopMostContainer(targetDummy); if ( isIdValid(structure) ) { if ( player_structure.isNameOnEntryList(structure, targetDummy.toString()) ) { permissionsRemoveAllowed(structure, targetDummy.toString()); } } return; } void removeTargetDummyFromPermissionsViaController(obj_id controller, obj_id targetDummy) { obj_id structure = getTopMostContainer(controller); if ( isIdValid(structure) ) { if ( player_structure.isNameOnEntryList(structure, targetDummy.toString()) ) { permissionsRemoveAllowed(structure, targetDummy.toString()); } } return; } obj_id setTargetDummyOwner(obj_id controller) { obj_id owner = getOwner(controller); if(isIdValid(owner)) { return owner; } else { CustomerServiceLog("target_dummy", "target_dummy.scriptlib:setTargetDummyOwner - The Target Dummy System is attempting to assign an owner for controller: "+controller); owner = utils.getContainingPlayer(controller); if ( isIdValid(owner) ) { setOwner(controller, owner); CustomerServiceLog("target_dummy", "target_dummy.scriptlib:setTargetDummyOwner - Target Dummy Controller: "+controller+" Ownership given to Owner OID: "+owner); } else { //LOG("target_dummy", "Target dummy owner was null and could not find a containing player."); } } return owner; } obj_id getTargetDummyOwnerFromController(obj_id controller) { return getOwner(controller); } obj_id getTargetDummyController(obj_id targetDummy) { obj_id controller = obj_id.NULL_ID; if ( hasObjVar(targetDummy, TARGET_DUMMY_CONTROLLER_OBJVAR) ) { controller = getObjIdObjVar(targetDummy, TARGET_DUMMY_CONTROLLER_OBJVAR); } return controller; } obj_id getTargetDummyId(obj_id controller) { obj_id targetDummy = obj_id.NULL_ID; if ( hasObjVar(controller, TARGET_DUMMY_ID_OBJVAR) ) { targetDummy = getObjIdObjVar(controller, TARGET_DUMMY_ID_OBJVAR); } return targetDummy; } string getTargetDummyCreatureType(obj_id controller) { string targetDummyCreatureType = "tcg_target_creature_acklay"; if ( hasObjVar(controller, target_dummy.CREATURE_NAME_OBJVAR) ) { targetDummyCreatureType = getStringObjVar(controller, target_dummy.CREATURE_NAME_OBJVAR); } return targetDummyCreatureType; } boolean permittedToCallTargetDummy(obj_id player, location here) { if( !isIdValid(player) || here == null ) { return false; } // God mode override to allow event team to place storyteller items with more freedom if ( isGod(player) ) { string logMsg = "("+player+")"+getName(player)+" is using GodMode override to deploy a target dummy at "+here; CustomerServiceLog("target_dummy", logMsg); sendSystemMessage(player, new string_id("target_dummy", "placement_god_mode")); return true; } obj_id myCell = here.cell; obj_id myContainer = getTopMostContainer(myCell); string planet = here.area; if( planet.startsWith("space_") ) { obj_id owner= getOwner(myContainer); if ( !isIdValid(owner) || owner != player ) { sendSystemMessage(player, new string_id("target_dummy", "placement_not_ship_owner")); return false; } if ( getState(player, STATE_SHIP_INTERIOR) != 1 || space_utils.isInStation(player) ) { sendSystemMessage(player, new string_id("target_dummy", "placement_not_in_station")); return false; } } else { if( !isIdValid(myCell) ) { sendSystemMessage(player, new string_id("target_dummy", "placement_not_outside")); return false; } else if ( !player_structure.isAdmin(myContainer, player) ) { sendSystemMessage(player, new string_id("target_dummy", "placement_not_building_admin")); return false; } } return true; } boolean controllerContainmentCheck(obj_id controller) { if ( !utils.isNestedWithinAPlayer(controller) ) { obj_id building = getTopMostContainer(controller); if ( isGameObjectTypeOf(building, GOT_building_player) || ( isGameObjectTypeOf(building, GOT_ship_fighter) && space_utils.isShipWithInterior(building) ) ) { location here = getLocation(controller); if ( getContainedBy(controller) == here.cell ) { return true; } } } return false; } boolean initializeTargetDummy(obj_id targetDummy, int combatLevel, int difficulty) { boolean result = false; string creatureName = getCreatureName(targetDummy); dictionary creatureDict = utils.dataTableGetRow(create.CREATURE_TABLE, creatureName); if ( creatureDict != null ) { creatureDict.put("difficultyClass", difficulty); create.initializeCreature(targetDummy, creatureName, creatureDict, combatLevel); setNpcDifficulty(targetDummy, difficulty); result = false; obj_id controller = target_dummy.getTargetDummyController(targetDummy); if ( isIdValid(controller) ) { setObjVar(controller, "intCombatDifficulty", combatLevel); setObjVar(controller, "difficultyClass", difficulty); } } return result; } int getTargetDummyDifficulty(obj_id targetDummy) { int difficulty = 0; if ( hasObjVar(targetDummy, "difficultyClass") ) { difficulty = getIntObjVar(targetDummy, "difficultyClass"); } return difficulty; } int getTargetDummyCombatLevel(obj_id targetDummy) { int level = 50; if ( hasObjVar(targetDummy, "intCombatDifficulty") ) { level = getIntObjVar(targetDummy, "intCombatDifficulty"); } return level; } void promptForCombatLevel(obj_id targetDummy, obj_id player) { string prompt = utils.packStringId(new string_id("target_dummy", "combat_level_prompt")); string name = utils.packStringId(new string_id("target_dummy", "combat_level_name")); //sui.inputbox(targetDummy, player, prompt, "handleTargetDummyLevelSelect"); sui.inputbox(targetDummy, player, prompt, sui.OK_CANCEL, name, sui.INPUT_NORMAL, null, "handleTargetDummyLevelSelect", null); return; } void promptForCombatDifficulty(obj_id targetDummy, obj_id player) { string title = utils.packStringId(new string_id("target_dummy", "combat_difficulty_title")); string prompt = utils.packStringId(new string_id("target_dummy","combat_difficulty_prompt")); string normal = utils.packStringId(new string_id("target_dummy", "difficulty_normal")); string elite = utils.packStringId(new string_id("target_dummy", "difficulty_elite")); string boss = utils.packStringId(new string_id("target_dummy", "difficulty_boss")); string [] difficulties = { normal, elite, boss }; int pid = sui.listbox(targetDummy, player, prompt, sui.OK_CANCEL, title, difficulties, "handleTargetDummyDifficultySelect"); return; } void showTargetDummyDefenseListSui(obj_id targetDummy, obj_id player) { if ( utils.hasScriptVar(player, "targetDummy.pidTargetDummyDefenses") ) { int oldPid = utils.getIntScriptVar(player, "targetDummy.pidTargetDummyDefenses"); forceCloseSUIPage(oldPid); } string title = utils.packStringId(new string_id("target_dummy", "combat_set_defenses_title")); string prompt = utils.packStringId(new string_id("target_dummy","combat_set_defenses_prompt")); int pid = sui.listbox(targetDummy, player, prompt, sui.OK_CANCEL, title, getTargetDummySkillModsOptions(targetDummy), "targetDummyDefenseTypeSelected"); if ( pid > -1 ) { utils.setScriptVar(player, "targetDummy.pidTargetDummyDefenses", pid); } return; } string[] getTargetDummySkillModsOptions(obj_id targetDummy) { string[] targetDummySkillMods = new string[TARGET_DUMMY_DEFENSES.length]; for ( int i=0; i < TARGET_DUMMY_DEFENSES.length; i++ ) { string skillModName = TARGET_DUMMY_DEFENSES[i]; string skillModOption = utils.packStringId(new string_id("target_dummy", TARGET_DUMMY_DEFENSES[i])); targetDummySkillMods[i] = skillModOption + " [current value: " + getEnhancedSkillStatisticModifier(targetDummy, skillModName) + "]"; } return targetDummySkillMods; } void promptForDefensiveValue(obj_id targetDummy, obj_id player, int skill_mod_selected) { utils.setScriptVar(player, "targetDummySkillModSelected", skill_mod_selected); string prompt = utils.packStringId(new string_id("target_dummy", "combat_defensive_skill_mod_prompt")); prompt += " " + utils.packStringId(new string_id("target_dummy", target_dummy.TARGET_DUMMY_DEFENSES[skill_mod_selected])) +" :"; sui.inputbox(targetDummy, player, prompt, "handleTargetDummyDefensiveSkillModSet"); return; } void setTargetDummyDefensiveValue(obj_id targetDummy, obj_id player, int value) { int skillModIndex = utils.getIntScriptVar(player, "targetDummySkillModSelected"); string skillModName = target_dummy.TARGET_DUMMY_DEFENSES[skillModIndex]; setTargetDummyDefensiveValue(targetDummy, player, value, skillModName); return; } void setTargetDummyDefensiveValue(obj_id targetDummy, obj_id player, int value, string skillModName) { int previousValue = getEnhancedSkillStatisticModifier(targetDummy, skillModName); if ( skillModName.equals("expertise_innate_protection_all") ) { if ( value < 0 || value > 12000 ) { if ( isIdValid(player) ) { sendSystemMessage(player, new string_id("target_dummy", "combat_armor_mod_invalid")); return; } } else { // First setting the skill mod to 0 so that the value that was input will be the new total value applySkillStatisticModifier(targetDummy, skillModName, 0-previousValue); applySkillStatisticModifier(targetDummy, skillModName, value); armor.recalculateArmorForMob(targetDummy); } } else { if ( value < 0 || value > 99 ) { if ( isIdValid(player) ) { sendSystemMessage(player, new string_id("target_dummy", "combat_skill_mod_invalid")); return; } } else { // First setting the skill mod to 0 so that the value that was input will be the new total value applySkillStatisticModifier(targetDummy, skillModName, 0-previousValue); applySkillStatisticModifier(targetDummy, skillModName, value); } } if ( isIdValid(player) ) { string_id message = new string_id ("target_dummy", "combat_skill_mod_set"); prose_package pp = prose.getPackage(message, player, player); prose.setTO(pp, utils.packStringId(new string_id("target_dummy", skillModName))); prose.setDI(pp, value); sendSystemMessageProse(player, pp); } obj_id controller = getTargetDummyController(targetDummy); if ( isIdValid(controller) ) { setObjVar(controller, "target_dummy_defense."+skillModName, value); } return; } void confirmClearYourCombatData(obj_id targetDummy, obj_id player) { string title = utils.packStringId(new string_id("target_dummy", "data_cleared_confirm_title")); string prompt = utils.packStringId(new string_id("target_dummy", "data_cleared_confirm_prompt")); string handler = "confirmClearYourCombatData"; buildConfirmClearCombatDataSui(targetDummy, player, title, prompt, handler); return; } void confirmClearAllCombatData(obj_id targetDummy, obj_id player) { string title = utils.packStringId(new string_id("target_dummy", "data_all_cleared_confirm_title")); string prompt = utils.packStringId(new string_id("target_dummy", "data_all_cleared_confirm_prompt")); string handler = "confirmClearAllCombatData"; buildConfirmClearCombatDataSui(targetDummy, player, title, prompt, handler); return; } void buildConfirmClearCombatDataSui(obj_id targetDummy, obj_id player, string title, string prompt, string handler) { string ok_button = utils.packStringId(new string_id ("quest/ground/util/quest_giver_object", "button_accept")); string cancel_button = utils.packStringId(new string_id ("quest/ground/util/quest_giver_object", "button_decline")); // Create the dialog page. int pid = sui.createSUIPage( sui.SUI_MSGBOX, targetDummy, player, handler); // Add elements text. setSUIProperty(pid, sui.MSGBOX_TITLE, sui.PROP_TEXT, title); setSUIProperty(pid, sui.MSGBOX_PROMPT, sui.PROP_TEXT, prompt); // Add buttons. sui.msgboxButtonSetup(pid, sui.YES_NO); setSUIProperty(pid, sui.MSGBOX_BTN_OK, sui.PROP_TEXT, ok_button); setSUIProperty(pid, sui.MSGBOX_BTN_CANCEL, sui.PROP_TEXT, cancel_button); // Show dialog. utils.setScriptVar(player, "clearCombatData.openSui", pid); sui.showSUIPage( pid ); return; } void clearYourCombatData(obj_id targetDummy, obj_id player) { obj_id controller = getTargetDummyController(targetDummy); if ( isIdValid(controller) && utils.hasScriptVarTree(controller, BASE_TARGET_DUMMY_VAR+"."+player) ) { utils.removeScriptVarTree(controller, BASE_TARGET_DUMMY_VAR+"."+player); sendSystemMessage(player, new string_id("target_dummy", "combat_data_clearing")); sendSystemMessage(player, new string_id("target_dummy", "combat_data_cleared")); // remove old combat data objvar that would have destroyed the entire game if ( hasObjVar(controller, target_dummy.BASE_TARGET_DUMMY_VAR) ) { removeObjVar(controller, target_dummy.BASE_TARGET_DUMMY_VAR); } } return; } void clearAllCombatData(obj_id targetDummy, obj_id player) { obj_id controller = getTargetDummyController(targetDummy); if ( isIdValid(controller) && utils.hasScriptVarTree(controller, BASE_TARGET_DUMMY_VAR) ) { utils.removeScriptVarTree(controller, BASE_TARGET_DUMMY_VAR); sendSystemMessage(player, new string_id("target_dummy", "combat_data_all_clearing")); sendSystemMessage(player, new string_id("target_dummy", "combat_data_all_cleared")); // remove old combat data objvar that would have destroyed the entire game if ( hasObjVar(controller, target_dummy.BASE_TARGET_DUMMY_VAR) ) { removeObjVar(controller, target_dummy.BASE_TARGET_DUMMY_VAR); } } return; } void sendTargetDummyCombatData(obj_id attacker, obj_id defender, combat_data actionData, hit_result hitData) { // this first check is currently intended for internal testing an stores the combat data on the attacker if ( utils.hasScriptVar(attacker, "testing_recordCombatData") ) { recoredCombatResult(attacker, attacker, actionData, hitData); } // if the defender is a target dummy, we store combat data on the defender if ( isTargetDummy(defender) ) { recoredCombatResultViaController(attacker, defender, actionData, hitData); } return; } void recoredCombatResultViaController(obj_id attacker, obj_id targetDummy, combat_data actionData, hit_result hitData) { obj_id controller = getTargetDummyController(targetDummy); if ( isIdValid(controller) ) { recoredCombatResult(attacker, controller, actionData, hitData); } return; } void recoredCombatResult(obj_id attacker, obj_id controller, combat_data actionData, hit_result hitData) { string attackUsed = actionData.actionName; boolean attackMissed = hitData.miss; boolean attackDodged = hitData.dodge; boolean attackParried = hitData.parry; int damageDone = hitData.damage; boolean criticalHit = hitData.critical; int criticalDamage = hitData.critDamage; boolean strikethroughHit = hitData.strikethrough; float strikethroughAmmount = hitData.strikethroughAmmount; boolean glancingHit = hitData.glancing; boolean evadedDamage = hitData.evadeResult; float evadeAmmount = hitData.evadeAmmount; boolean blockedHit = hitData.blockResult; int blockAmount = hitData.block; obj_id combatDataOwner = attacker; if ( beast_lib.isBeast(attacker) ) { combatDataOwner = getMaster(attacker); } string baseAttackerVar = BASE_TARGET_DUMMY_VAR+"."+combatDataOwner; string baseAllAttacksVar = baseAttackerVar+"."+ ALL_ATTACKS_SUB_VAR; string baseSpecificAttackVar = baseAttackerVar+"."+attackUsed; int[] allAttacksData = new int[ATTACK_DATA_ARRAY.length]; if ( utils.hasScriptVarTree(controller, baseAllAttacksVar) ) { allAttacksData = utils.getIntArrayScriptVar(controller, baseAllAttacksVar); } else { for ( int i = 0; i < allAttacksData.length; i++ ) { allAttacksData[i] = 0; } } int[] specificAttackData = new int[ATTACK_DATA_ARRAY.length]; if ( utils.hasScriptVarTree(controller, baseSpecificAttackVar) ) { specificAttackData = utils.getIntArrayScriptVar(controller, baseSpecificAttackVar); } else { for ( int i = 0; i < specificAttackData.length; i++ ) { specificAttackData[i] = 0; } } storeCumulativeCombatData(allAttacksData, INDEX_NUM_OF_ATTACKS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_OF_ATTACKS, 1); // No damage...attack was dodged, parried, or just missed. if ( !hitData.success ) { //sendSystemMessage(combatDataOwner, "An attack was missed, dodged, or parried...", ""); int indexOfAvoidanceType = -1; int numAvoided = 1; if ( attackMissed ) { indexOfAvoidanceType = INDEX_NUM_MISSED; } else if ( attackDodged ) { indexOfAvoidanceType = INDEX_NUM_DODGED; } else if ( attackParried ) { indexOfAvoidanceType = INDEX_NUM_PARRIED; } else { // the attack was unsuccessful for some other reason. // The target dummy is going to call that a Miss. indexOfAvoidanceType = INDEX_NUM_MISSED; } if ( indexOfAvoidanceType > -1 ) { storeCumulativeCombatData(allAttacksData, indexOfAvoidanceType, 1); storeCumulativeCombatData(specificAttackData, indexOfAvoidanceType, 1); } } else // Some damage was done. Recording the results. { // total amount of damage done this session from all attacks storeCumulativeCombatData(allAttacksData, INDEX_TOTAL_DAMAGE_DONE, damageDone); // get largest and smallest overall individual attack storeComparisonCombatData(allAttacksData, damageDone); // damage done by attack type storeCumulativeCombatData(specificAttackData, INDEX_TOTAL_DAMAGE_DONE, damageDone); // get largest and smallest attack by type storeComparisonCombatData(specificAttackData, damageDone); // critical hit data if ( criticalHit ) { storeCumulativeCombatData(allAttacksData, INDEX_NUM_CRITAL_HITS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_CRITAL_HITS, 1); } // strikethrough hit data if ( strikethroughHit ) { storeCumulativeCombatData(allAttacksData, INDEX_NUM_STRIKETHROUGH, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_STRIKETHROUGH, 1); } // glancing hit data if ( glancingHit ) { storeCumulativeCombatData(allAttacksData, INDEX_NUM_GLANCING_HITS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_GLANCING_HITS, 1); } // evaded damage data if ( evadedDamage ) { storeCumulativeCombatData(allAttacksData, INDEX_NUM_EVADED_HITS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_EVADED_HITS, 1); } // blocked hit data if ( blockedHit ) { storeCumulativeCombatData(allAttacksData, INDEX_NUM_BLOCKED_HITS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_BLOCKED_HITS, 1); } // total successful attacks storeCumulativeCombatData(allAttacksData, INDEX_NUM_SUCCESSFUL_HITS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_SUCCESSFUL_HITS, 1); // num normal hits if ( recordAsNormalHit(hitData) ) { storeCumulativeCombatData(allAttacksData, INDEX_NUM_NORMAL_HITS, 1); storeCumulativeCombatData(specificAttackData, INDEX_NUM_NORMAL_HITS, 1); } } utils.setScriptVar(controller, baseAllAttacksVar, allAttacksData); utils.setScriptVar(controller, baseSpecificAttackVar, specificAttackData); utils.setScriptVar(controller, baseAttackerVar + "." + LAST_ATTACK_TIME_VAR, getGameTime()); return; } void storeCumulativeCombatData(int[] dataArray, int index, int newData) { int previousData = dataArray[index]; dataArray[index] = previousData + newData; return; } void storeComparisonCombatData(int[] dataArray, int newData) { int previousLargest = dataArray[INDEX_LARGEST_ATTACK]; if ( newData >= previousLargest ) { dataArray[INDEX_LARGEST_ATTACK] = newData; } int previousSmallest = newData; if ( dataArray[INDEX_SMALLEST_ATTACK] > 0 ) { previousSmallest = dataArray[INDEX_SMALLEST_ATTACK]; } if ( newData <= previousSmallest ) { dataArray[INDEX_SMALLEST_ATTACK] = newData; } return; } boolean recordAsNormalHit(hit_result hitData) { boolean criticalHit = hitData.critical; boolean strikethroughHit = hitData.strikethrough; boolean glancingHit = hitData.glancing; boolean evadedDamage = hitData.evadeResult; boolean blockedHit = hitData.blockResult; if ( !criticalHit && !strikethroughHit ) { return true; } return false; } void reportCombatData(obj_id player, obj_id targetDummy) { reportCombatDataViaController(player, targetDummy, obj_id.NULL_ID); return; } void reportCombatDataViaController(obj_id player, obj_id targetDummy, obj_id controller) { // If the control object isn't null, that is where the report data should be. // Otherwise it should be on the object sent as the targetDummy obj_id reportDataObject = targetDummy; if ( isIdValid(controller) ) { reportDataObject = controller; } // remove old combat data objvar that would have destroyed the entire game if ( hasObjVar(reportDataObject, target_dummy.BASE_TARGET_DUMMY_VAR) ) { removeObjVar(reportDataObject, target_dummy.BASE_TARGET_DUMMY_VAR); } string baseAttackerVar = BASE_TARGET_DUMMY_VAR+"."+player; if ( utils.hasScriptVarTree(reportDataObject, baseAttackerVar) ) { string report = getCombatDataReportString(reportDataObject, player); if ( utils.hasScriptVar(player, "target_dummy.openCombatReportSui") ) { int oldPid = utils.getIntScriptVar(player, "target_dummy.openCombatReportSui"); forceCloseSUIPage(oldPid); } // Create the dialog page. int pid = sui.createSUIPage(sui.SUI_MSGBOX, targetDummy, player, "handleTargetDummyCombatReport"); // Add elements text. setSUIProperty(pid, sui.MSGBOX_TITLE, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_title")) ); setSUIProperty(pid, sui.MSGBOX_PROMPT, sui.PROP_TEXT, report); // Add buttons. sui.msgboxButtonSetup(pid, sui.YES_NO_CANCEL); setSUIProperty(pid, sui.MSGBOX_BTN_OK, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_refreshbutton"))); setSUIProperty(pid, sui.MSGBOX_BTN_REVERT, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_clear_button"))); setSUIProperty(pid, sui.MSGBOX_BTN_CANCEL, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_closebutton"))); setSUIProperty(pid, sui.MSGBOX_BTN_REVERT, "OnPress", "RevertWasPressed=1\r\nparent.btnOk.press=t"); subscribeToSUIProperty(pid, sui.MSGBOX_BTN_REVERT, "RevertWasPressed"); // Show dialog. utils.setScriptVar(player, "target_dummy.openCombatReportSui", pid); sui.showSUIPage(pid); } else { sendSystemMessage(player, new string_id("target_dummy", "placement_no_combat_data")); } return; } string getCombatDataReportString(obj_id reportDataObject, obj_id player) { string report = ""; string baseAttackerVar = BASE_TARGET_DUMMY_VAR+"."+player; if ( utils.hasScriptVarTree(reportDataObject, baseAttackerVar) ) { deltadictionary vars = reportDataObject.getScriptVars(); resizeable string[] attackTypes = new string[]; Enumeration keys = vars.keys(); while ( keys.hasMoreElements() ) { string key = (string)(keys.nextElement()); if ( key.startsWith(baseAttackerVar + ".") ) { string[] data = split(key, '.'); // data[0] = target_dummy // data[1] = player obj_id // data[2] = attack type string attackType = data[2]; if ( !attackType.equals(LAST_ATTACK_TIME_VAR) ) { utils.addElement(attackTypes, attackType); } } } int numItems = attackTypes.length; string[] initialAttackTypes = new string[numItems-1]; int[] initialDamageDoneArray = new int[numItems-1]; string[] sortedAttackTypes = new string[numItems]; int initialIdx = 0; for ( int i = 0; i < numItems; i++ ) { string attackName = attackTypes[i]; if ( attackName.equals(ALL_ATTACKS_SUB_VAR) ) { sortedAttackTypes[0] = attackName; } else { initialAttackTypes[initialIdx] = attackName; string baseSpecificAttackVar = baseAttackerVar+"."+attackName; int[] tempAttackData = utils.getIntArrayScriptVar(reportDataObject, baseSpecificAttackVar); initialDamageDoneArray[initialIdx] = tempAttackData[INDEX_TOTAL_DAMAGE_DONE]; initialIdx = initialIdx + 1; } } int[] ascendingDataArray = new int[initialDamageDoneArray.length]; utils.copyArray(initialDamageDoneArray, ascendingDataArray); Arrays.sort(ascendingDataArray); for ( int j = 0; j < ascendingDataArray.length; j++ ) { int data = ascendingDataArray[j]; int index = utils.getElementPositionInArray(initialDamageDoneArray, data); string name = initialAttackTypes[index]; sortedAttackTypes[(ascendingDataArray.length) - j] = name; initialDamageDoneArray[index] = -1; } int numAttackTypes = sortedAttackTypes.length; report = utils.packStringId(REPORT_TITLE_SID) + addLineBreaks(1); for ( int idx = 0; idx < numAttackTypes; idx++ ) { string attackTypeName = sortedAttackTypes[idx]; string attackTypeVarName = baseAttackerVar+"."+attackTypeName; int[] attackData = utils.getIntArrayScriptVar(reportDataObject, attackTypeVarName); int numAttacks = attackData[INDEX_NUM_OF_ATTACKS]; int totalDamageDone = attackData[INDEX_TOTAL_DAMAGE_DONE]; int largestAttack = attackData[INDEX_LARGEST_ATTACK]; int smallestAttack = attackData[INDEX_SMALLEST_ATTACK]; int numCriticalHits = attackData[INDEX_NUM_CRITAL_HITS]; int numStrikethroughHit = attackData[INDEX_NUM_STRIKETHROUGH]; int numMissed = attackData[INDEX_NUM_MISSED]; int numDodged = attackData[INDEX_NUM_DODGED]; int numParried = attackData[INDEX_NUM_PARRIED]; int numGlancingHit = attackData[INDEX_NUM_GLANCING_HITS]; int numEvadedDamage = attackData[INDEX_NUM_EVADED_HITS]; int numBlockedHit = attackData[INDEX_NUM_BLOCKED_HITS]; int numSuccessfulAttacks = attackData[INDEX_NUM_SUCCESSFUL_HITS]; int numNormalHits = attackData[INDEX_NUM_NORMAL_HITS]; int averageDamage = totalDamageDone/numAttacks; float percentageMissed = getPercentage(numMissed, numAttacks); float percentageDodged = getPercentage(numDodged, numAttacks); float percentageParried = getPercentage(numParried, numAttacks); float percentageCrit = getPercentage(numCriticalHits, numAttacks); float percentageStrikethrough = getPercentage(numStrikethroughHit, numAttacks); float percentageGlancing = getPercentage(numGlancingHit, numAttacks); float percentageEvaded = getPercentage(numEvadedDamage, numAttacks); float percentageBlocked = getPercentage(numBlockedHit, numAttacks); float percentageNormal = getPercentage(numNormalHits, numAttacks); report += YELLOW + utils.packStringId(REPORT_ATTACK_TYPE_SID); report += WHITE + utils.packStringId(new string_id("cmd_n", attackTypeName)) + addLineBreaks(1); report += GREEN + utils.packStringId(REPORT_NUM_ATTACKS_SID) + WHITE + numAttacks + addLineBreaks(1); report += GREEN + utils.packStringId(REPORT_TOTAL_DAMAGE_SID) + WHITE + totalDamageDone + addLineBreaks(1); report += GREEN + utils.packStringId(REPORT_AVERAGE_DAMAGE_SID) + WHITE + averageDamage + addLineBreaks(1); report += GREEN + utils.packStringId(REPORT_SMALLEST_ATTACK_SID) + WHITE + smallestAttack + addLineBreaks(1); report += GREEN + utils.packStringId(REPORT_LARGEST_ATTACK_SID) + WHITE + largestAttack + addLineBreaks(2); report += BLUE + utils.packStringId(REPORT_NUM_SUCCESSFUL_SID) + WHITE + numSuccessfulAttacks + addLineBreaks(1); // report += BLUE + utils.packStringId(REPORT_NUM_NORMAL_SID) + WHITE + numNormalHits + " ( "+ percentageNormal+ percentSign() + addLineBreaks(1); report += BLUE + utils.packStringId(REPORT_NUM_CRITS_SID) + WHITE + numCriticalHits + " ( "+ percentageCrit+ percentSign() + addLineBreaks(1); report += BLUE + utils.packStringId(REPORT_NUM_STRIKETHROUGH_SID) + WHITE + numStrikethroughHit + " ( " + percentageStrikethrough + percentSign() + addLineBreaks(2); report += ORANGE + utils.packStringId(REPORT_NUM_GLANCING_SID) + WHITE + numGlancingHit + " ( " + percentageGlancing + percentSign() + addLineBreaks(1); report += ORANGE + utils.packStringId(REPORT_NUM_EVADES_SID) + WHITE + numEvadedDamage + " ( " + percentageEvaded + percentSign() + addLineBreaks(1); report += ORANGE + utils.packStringId(REPORT_NUM_BLOCKED_SID) + WHITE + numBlockedHit + " ( " + percentageBlocked + percentSign() + addLineBreaks(2); report += RED + utils.packStringId(REPORT_NUM_MISSES_SID) + WHITE + numMissed + " ( " + percentageMissed + percentSign() + addLineBreaks(1); report += RED + utils.packStringId(REPORT_NUM_DODGES_SID) + WHITE + numDodged + " ( " + percentageDodged + percentSign() + addLineBreaks(1); report += RED + utils.packStringId(REPORT_NUM_PARRIES_SID) + WHITE + numParried + " ( "+ percentageParried + percentSign() + addLineBreaks(1); report += WHITE + utils.packStringId(REPORT_LINE_BREAK_SID)+ addLineBreaks(2); } } else { report = utils.packStringId(new string_id("target_dummy", "placement_no_combat_data")); } return report; } void showRawCombatDataViaController(obj_id player, obj_id targetDummy) { if ( isGod(player) ) { obj_id controller = target_dummy.getTargetDummyController(targetDummy); if ( isIdValid(controller) ) { showRawCombatData(player, controller); } } return; } void showRawCombatData(obj_id player, obj_id controller) { if ( isGod(player) ) { string report = ""; string baseAttackerVar = BASE_TARGET_DUMMY_VAR+"."+player; if ( utils.hasScriptVarTree(controller, baseAttackerVar) ) { deltadictionary vars = controller.getScriptVars(); resizeable string[] attackTypes = new string[]; Enumeration keys = vars.keys(); while ( keys.hasMoreElements() ) { string key = (string)(keys.nextElement()); if ( key.startsWith(baseAttackerVar + ".") ) { string[] data = split(key, '.'); // data[0] = target_dummy // data[1] = player obj_id // data[2] = attack type string attackType = data[2]; if ( !attackType.equals(LAST_ATTACK_TIME_VAR) ) { utils.addElement(attackTypes, attackType); } } } report = utils.packStringId(REPORT_TITLE_SID) + addLineBreaks(1); for ( int i = 0; i < attackTypes.length; i++ ) { string attackTypeName = attackTypes[i]; string attackTypeVarName = baseAttackerVar+"."+attackTypeName; int[] attackData = utils.getIntArrayScriptVar(controller, attackTypeVarName); report += attackTypeName + ": { "; for ( int j = 0; j < attackData.length; j++ ) { report += attackData[j]; if ( j == attackData.length - 1 ) { report += " }" + sui.newLine(); } else { report += ", "; } } } } else { report = utils.packStringId(new string_id("target_dummy", "placement_no_combat_data")); } if ( utils.hasScriptVar(player, "target_dummy.rawCombatReportSui") ) { int oldPid = utils.getIntScriptVar(player, "target_dummy.rawCombatReportSui"); forceCloseSUIPage(oldPid); } // Create the dialog page. int pid = sui.createSUIPage(sui.SUI_MSGBOX, controller, player, "noRawCombatDataTargetDummyHandler"); // Add elements text. setSUIProperty(pid, sui.MSGBOX_TITLE, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_title")) ); setSUIProperty(pid, sui.MSGBOX_PROMPT, sui.PROP_TEXT, report); // Add buttons. sui.msgboxButtonSetup(pid, sui.YES_NO); setSUIProperty(pid, sui.MSGBOX_BTN_OK, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_refreshbutton"))); setSUIProperty(pid, sui.MSGBOX_BTN_CANCEL, sui.PROP_TEXT, utils.packStringId(new string_id("target_dummy", "report_closebutton"))); // Show dialog. utils.setScriptVar(player, "target_dummy.rawCombatReportSui", pid); sui.showSUIPage(pid); } return; } float getPercentage(float num, float total) { float answer = num*10000/total; int truncated = (int)answer; return (float)truncated/100; } void removeCombatAi(obj_id targetDummy) { removeTriggerVolume(ai_lib.ALERT_VOLUME_NAME); removeTriggerVolume(ai_lib.AGGRO_VOLUME_NAME); if ( hasScript(targetDummy, "ai.creature_combat") ) { detachScript(targetDummy, "ai.creature_combat"); } return; } void freezeMob(obj_id targetDummy) { ai_lib.setDefaultCalmBehavior(targetDummy, ai_lib.BEHAVIOR_SENTINEL); ai_lib.aiStopFollowing(targetDummy); //setState(targetDummy, STATE_FROZEN, true); } void setFullHealth(obj_id targetDummy) { int maxHealth = getUnmodifiedMaxAttrib(targetDummy, HEALTH); setAttrib(targetDummy, HEALTH, maxHealth); } void endTargetDummyCombat(obj_id targetDummy, obj_id player) { if(ai_lib.isInCombat(targetDummy) || ai_lib.isInCombat(player)) { obj_id[] enemies = getHateList(targetDummy); setCombatTarget(targetDummy, obj_id.NULL_ID); stopCombat(targetDummy); ai_lib.clearCombatData(); utils.removeScriptVarTree(targetDummy,"ai.combat"); setFullHealth(targetDummy); removeAttackerFromCombat(targetDummy, player); if ( enemies != null && enemies.length > 0 ) { for ( int i=0; i < enemies.length; i++ ) { obj_id enemy = enemies[i]; if ( isIdValid(enemy) && enemy != player ) { removeAttackerFromCombat(targetDummy, enemy); } } } location where = getLocation(targetDummy); if(where == null) return; obj_id controller = getObjIdObjVar(targetDummy, TARGET_DUMMY_CONTROLLER_OBJVAR); if(!isValidId(controller)) return; if(isValidId(createTargetDummyAtLocation(controller, player, where))) destroyObject(targetDummy); } return; } void removeAttackerFromCombat(obj_id targetDummy, obj_id player) { removeHateTarget(targetDummy, player); removeHateTarget(player, targetDummy); stopCombat(player); return; } void enterIntoCombat(obj_id targetDummy, obj_id player) { //debugSpeakMsg(targetDummy, "enterIntoCombat called...forced into combat."); startCombat(targetDummy, player); addHate(targetDummy, player, 1000.0f); //startCombatWithAssist(targetDummy, player); return; } /*************************************************************************/ /*** EXTRAS ***/ const string DATA = "datatables/tcg/target_dummy_extras.iff"; const string TYPE_COLUMN = "target_dummy_type"; const string RANDON_ANIM_COLUMN = "random_anims"; const string TRICK_ANIM_COLUMN = "trick_anims"; const string TARGET_DUMMY_LAST_EXTRAS_ANIM = "targetDummyLastAnim"; const string[] EXTRA_TYPES = { RANDON_ANIM_COLUMN, TRICK_ANIM_COLUMN }; boolean hasTargetDummyExtras(obj_id targetDummy) { for ( int i = 0; i < EXTRA_TYPES.length; i++ ) { string testExtra = getTargetDummyAnim(targetDummy, EXTRA_TYPES[i]); if ( testExtra != null && testExtra.length() > 0 ) { return true; } } return false; } boolean hasTargetDummyRandomAnim(obj_id targetDummy) { string testAnim = getTargetDummyAnim(targetDummy, RANDON_ANIM_COLUMN); if ( testAnim != null && testAnim.length() > 0 ) { return true; } return false; } boolean hasTargetDummyTrickAnim(obj_id targetDummy) { string testTrick = getTargetDummyAnim(targetDummy, TRICK_ANIM_COLUMN); if ( testTrick != null && testTrick.length() > 0 ) { return true; } return false; } void doTargetDummyRandomAnim(obj_id targetDummy) { string animName = getTargetDummyAnim(targetDummy, RANDON_ANIM_COLUMN); doTargetDummyAnimation(targetDummy, animName); return; } void doTargetDummyTrick(obj_id targetDummy) { string trickName = getTargetDummyAnim(targetDummy, TRICK_ANIM_COLUMN); doTargetDummyAnimation(targetDummy, trickName); return; } string getTargetDummyAnim(obj_id targetDummy, string column) { string anims = getTargetDummyExtrasData(targetDummy, column); if ( anims != null && anims.length() > 0 ) { string[] animsList = split(anims, ','); if ( animsList != null && animsList.length > 0 ) { int randAnim = rand(0, animsList.length-1); return animsList[randAnim]; } } return ""; } void doTargetDummyAnimation(obj_id targetDummy, string animName) { if ( animName != null && animName.length() > 0 ) { doAnimationAction(targetDummy, animName); setObjVar(targetDummy, TARGET_DUMMY_LAST_EXTRAS_ANIM, animName); } return; } string getTargetDummyExtrasData(obj_id targetDummy, string column) { string result = ""; string type = getCreatureName(targetDummy); if ( type != null && type.length() > 0 ) { dictionary targetDummyExtras = dataTableGetRow(DATA, type); if ( targetDummyExtras != null && !targetDummyExtras.isEmpty() ) { result = targetDummyExtras.getString(column); } } return result; } /*************************************************************************/ boolean blog(string msg) { if(msg == null || msg.equals("")) return false; if(LOGGING_ON) LOG(TERMINAL_LOGGING, msg); return true; }