Initial commit
This commit is contained in:
519
DATA/SCRIPTS/LIBRARY/PGEVENTS.LUA
Normal file
519
DATA/SCRIPTS/LIBRARY/PGEVENTS.LUA
Normal file
@@ -0,0 +1,519 @@
|
||||
--/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
-- (c) Galyana's Ultimate Empire at War Modifications
|
||||
--
|
||||
-- ****** *** *** ************ *** ***
|
||||
-- * * * * * * * *
|
||||
-- * * * * * * *
|
||||
-- * * * * * * *
|
||||
-- * * * * * **** * * *
|
||||
-- * * * ****** * * * *
|
||||
-- * **** * * * * * * * *** *
|
||||
-- * * * * * * * * * *
|
||||
-- * * * * * * * * * *
|
||||
-- * * * * * * * ** * * *
|
||||
-- ****** ****** ************ **** ** *******
|
||||
--/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
-- C O N F I D E N T I A L S O U R C E C O D E -- D O N O T D I S T R I B U T E
|
||||
--/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
--
|
||||
-- File: GUEaW/Data/Scripts/Library/PGEvents.LUA
|
||||
--
|
||||
-- Original Editor: Giovanni Galyana
|
||||
--
|
||||
-- Final Edit By: Giovanni Galyana
|
||||
--
|
||||
-- Date: 7 March, 2015
|
||||
--
|
||||
-- Revisions: 0
|
||||
--
|
||||
--/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
--
|
||||
-- Default Event Handlers.
|
||||
--
|
||||
|
||||
require("PGTaskForce")
|
||||
|
||||
function GoHeal(tf, unit, healer, release)
|
||||
|
||||
--If we can lay proximity mines, do so and then rely on a further call to kite the enemy over them
|
||||
--Add a random factor here since proximity mines currently have no cooldown and so we'll never run
|
||||
--because we can always use them
|
||||
if (GameRandom.Get_Float() > 0.5) and Try_Ability(unit, "PROXIMITY_MINES", unit) then
|
||||
return
|
||||
end
|
||||
|
||||
if Try_Ability(unit, "BUZZ_DROIDS", unit) then
|
||||
return
|
||||
end
|
||||
|
||||
if release then
|
||||
Try_Ability(unit,"JET_PACK", healer)
|
||||
Try_Ability(unit,"SPRINT")
|
||||
Try_Ability(unit, "FORCE_CLOAK")
|
||||
Try_Ability(unit, "STEALTH")
|
||||
unit.Move_To(healer, 10)
|
||||
unit.Lock_Current_Orders()
|
||||
tf.Release_Unit(unit)
|
||||
else
|
||||
Try_Ability(unit,"JET_PACK", healer)
|
||||
Try_Ability(unit,"SPRINT")
|
||||
Try_Ability(unit, "FORCE_CLOAK")
|
||||
Try_Ability(unit, "STEALTH")
|
||||
unit.Divert(healer)
|
||||
end
|
||||
end
|
||||
|
||||
function GoKite(tf, unit, kite_pos, release)
|
||||
|
||||
--If we can lay proximity mines, do so and then rely on a further call to kite the enemy over them
|
||||
--Add a random factor here since proximity mines currently have no cooldown and so we'll never run
|
||||
--because we can always use them
|
||||
if (GameRandom.Get_Float() > 0.5) and Try_Ability(unit, "PROXIMITY_MINES", unit) then
|
||||
return
|
||||
end
|
||||
|
||||
if Try_Ability(unit, "BUZZ_DROIDS", unit) then
|
||||
return
|
||||
end
|
||||
|
||||
if release then
|
||||
Try_Ability(unit,"Turbo") -- Enable Turbo mode, if we have it.
|
||||
Try_Ability(unit,"JET_PACK", kite_pos)
|
||||
Try_Ability(unit,"EJECT_VEHICLE_THIEF")
|
||||
Try_Ability(unit,"SPRINT")
|
||||
Try_Ability(unit, "SPOILER_LOCK")
|
||||
Try_Ability(unit, "REPLENISH_WINGMEN")
|
||||
Try_Ability(unit, "FORCE_CLOAK")
|
||||
Try_Ability(unit, "STEALTH")
|
||||
if unit.Get_Hull() > 0.5 then
|
||||
Try_Ability(unit, "STIM_PACK")
|
||||
end
|
||||
|
||||
unit.Move_To(kite_pos)
|
||||
unit.Lock_Current_Orders()
|
||||
tf.Release_Unit(unit)
|
||||
else
|
||||
if not unit.Is_On_Diversion() then
|
||||
--MessageBox("%s -- Diverting: %s", tostring(Script), tostring(unit))
|
||||
Try_Ability(unit,"Turbo") -- Enable Turbo mode, if we have it.
|
||||
Try_Ability(unit,"JET_PACK", kite_pos)
|
||||
Try_Ability(unit,"EJECT_VEHICLE_THIEF")
|
||||
Try_Ability(unit,"SPRINT")
|
||||
Try_Ability(unit, "SPOILER_LOCK")
|
||||
Try_Ability(unit, "REPLENISH_WINGMEN")
|
||||
Try_Ability(unit, "FORCE_CLOAK")
|
||||
Try_Ability(unit, "STEALTH")
|
||||
if unit.Get_Hull() > 0.5 then
|
||||
Try_Ability(unit, "STIM_PACK")
|
||||
end
|
||||
|
||||
unit.Divert(kite_pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Try_Good_Ground(tf, unit)
|
||||
|
||||
nearest_good_ground_indicator = Find_Nearest(unit, "Prop_Good_Ground_Area")
|
||||
if nearest_good_ground_indicator then
|
||||
dist_to_good_ground = unit.Get_Distance(nearest_good_ground_indicator)
|
||||
if (dist_to_good_ground < 300) and (dist_to_good_ground > 20) then
|
||||
|
||||
unit.Activate_Ability("SPREAD_OUT", false)
|
||||
unit.Move_To(nearest_good_ground_indicator)
|
||||
unit.Lock_Current_Orders()
|
||||
tf.Release_Unit(unit)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- This should be useful for getting units within the minimum attack range
|
||||
-- or outside the maximum attack range on opponents who behave like artillery
|
||||
function Respond_To_MinRange_Attacks(tf, unit)
|
||||
|
||||
DebugMessage("%s-- looking at attacker for minrange response", tostring(Script))
|
||||
|
||||
min_range_attackers = {
|
||||
"R_Ground_Turbolaser_Tower"
|
||||
,"E_Ground_Turbolaser_Tower"
|
||||
,"U_Ground_Turbolaser_Tower"
|
||||
,"H_Ground_Turbolaser_Tower"
|
||||
,"H_Ground_Heavy_Beam_Tower"
|
||||
,"FCU_E_Ground_Turbolaser_Tower"
|
||||
,"FCU_R_Ground_Turbolaser_Tower"
|
||||
,"FCU_U_Ground_Turbolaser_Tower"
|
||||
,"FCU_H_Ground_Heavy_Beam_Tower"
|
||||
,"MPTL"
|
||||
,"SPMAT_Walker"
|
||||
,"AALL6"
|
||||
,"Hutt_SailBarge"
|
||||
,"Marauder_Missile_Cruiser"
|
||||
,"Broadside_Class_Cruiser"
|
||||
}
|
||||
|
||||
deadly_enemy = FindDeadlyEnemy(unit)
|
||||
if TestValid(deadly_enemy) then
|
||||
deadly_enemy_type = deadly_enemy.Get_Type()
|
||||
if Is_Type_In_List(deadly_enemy_type, min_range_attackers) then
|
||||
DebugMessage("%s -- attacked by min range attacker", tostring(Script))
|
||||
|
||||
-- Move any units in the task force which are in range of the attacker
|
||||
-- to a position over the max range or under the min range
|
||||
approach_or_flee_range = ((deadly_enemy_type.Get_Max_Range() - deadly_enemy_type.Get_Min_Range()) * 2 / 3) + deadly_enemy_type.Get_Min_Range()
|
||||
for i, tf_unit in pairs(tf.Get_Unit_Table()) do
|
||||
DebugMessage("%s -- considering run or approach for %s", tostring(Script), tostring(tf_unit))
|
||||
distance = tf_unit.Get_Distance(deadly_enemy)
|
||||
if distance < deadly_enemy_type.Get_Max_Range() then
|
||||
if distance < approach_or_flee_range then
|
||||
DebugMessage("%s -- trying to run inside min attack range", tostring(Script))
|
||||
tf_unit.Move_To(deadly_enemy)
|
||||
tf_unit.Lock_Current_Orders()
|
||||
tf.Release_Unit(unit)
|
||||
else
|
||||
DebugMessage("%s -- trying to run outside max attack range", tostring(Script))
|
||||
GoKite(tf, tf_unit, Project_By_Unit_Range(deadly_enemy, tf_unit))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function Is_Type_In_List(unit_type, type_name_list)
|
||||
for i, type_name in pairs(type_name_list) do
|
||||
DebugMessage("%s -- type:%s checking match to:%s", tostring(Script), unit_type.Get_Name(), type_name)
|
||||
if unit_type == Find_Object_Type(type_name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check if the passed ability is one of the type that the AI wants to turn back on when cancelled
|
||||
function IsAbilityAllowedToRecover(ability)
|
||||
allowed_abilities = {
|
||||
"SPOILER_LOCK"
|
||||
,"Turbo"
|
||||
}
|
||||
|
||||
for i, allowed_ability in pairs(allowed_abilities) do
|
||||
if ability == allowed_ability then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Default_Space_Conflict_Begin()
|
||||
DebugMessage("%s -- In Default_Space_Conflict_Begin.", tostring(Script))
|
||||
InSpaceConflict = true
|
||||
GlobalValue.Set(PlayerSpecificName(PlayerObject, "CONTACT_OCCURED"), 0.0)
|
||||
end
|
||||
|
||||
function Default_Space_Conflict_End()
|
||||
DebugMessage("%s -- In Default_Space_Conflict_End.", tostring(Script))
|
||||
InSpaceConflict = false
|
||||
GlobalValue.Set(PlayerSpecificName(PlayerObject, "CONTACT_OCCURED"), 0.0)
|
||||
end
|
||||
|
||||
function Default_Unit_Destroyed()
|
||||
DebugMessage("%s -- In Default_Unit_Destroyed.", tostring(Script))
|
||||
end
|
||||
|
||||
function Default_Unit_Damaged(tf, unit, attacker, deliberate)
|
||||
DebugMessage("%s -- In Default_Unit_Damaged.", tostring(Script))
|
||||
|
||||
if not TestValid(unit) or not TestValid(attacker) or attacker.Is_Category("Structure") then
|
||||
return
|
||||
end
|
||||
|
||||
lib_issued_movement_response = false
|
||||
|
||||
-- all units but Interdictors try to maneuver against artillery and turbolasers
|
||||
-- Interdictors should use missile shield instead
|
||||
if unit.Get_Type() ~= Find_Object_Type("Interdictor_Cruiser") then
|
||||
lib_issued_movement_response = Respond_To_MinRange_Attacks(tf, unit)
|
||||
end
|
||||
|
||||
if Should_Crush(unit, attacker) then
|
||||
unit.Divert(Project_By_Unit_Range(unit, attacker))
|
||||
lib_issued_movement_response = true
|
||||
end
|
||||
|
||||
-- If the unit is infantry, try to use any nearby garrisons or "good ground"
|
||||
if unit.Is_Category("Infantry") then
|
||||
|
||||
if not lib_issued_movement_response then
|
||||
lib_issued_movement_response = Try_Garrison(tf, unit, unit.Get_Hull() > 0.4, 300.0)
|
||||
end
|
||||
|
||||
if not lib_issued_movement_response then
|
||||
lib_issued_movement_response = Try_Good_Ground(tf, unit)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if attacker.Is_Category("Infantry") then
|
||||
Try_Deploy_Garrison(unit, attacker, 0.5)
|
||||
end
|
||||
|
||||
-- Use "Power to Shields" if this unit has it and it's ready
|
||||
lib_ability_activated = false
|
||||
lib_shield_level = unit.Get_Shield()
|
||||
if lib_shield_level < 0.2 then
|
||||
lib_ability_activated = Try_Ability(unit, "INVULNERABILITY")
|
||||
end
|
||||
|
||||
if (not lib_ability_activated) and (lib_shield_level < 0.8) then
|
||||
lib_ability_activated = Try_Ability(unit, "Defend")
|
||||
end
|
||||
|
||||
projectile_type = attacker.Get_Current_Projectile_Type()
|
||||
if TestValid(projectile_type) then
|
||||
if (not lib_ability_activated) and projectile_type.Is_Affected_By_Missile_Shield() then
|
||||
lib_ability_activated = Try_Ability(unit, "SENSOR_JAMMING") or Try_Ability(unit, "MISSILE_SHIELD")
|
||||
end
|
||||
|
||||
if (not lib_ability_activated) and projectile_type.Is_Affected_By_Laser_Defense() then
|
||||
lib_ability_activated = Try_Ability(unit, "LASER_DEFENSE")
|
||||
end
|
||||
end
|
||||
|
||||
--Everything below deals with movement orders
|
||||
if lib_issued_movement_response then
|
||||
return
|
||||
end
|
||||
|
||||
-- non-hero fighters will always willingly dogfight other fighters
|
||||
if deliberate and attacker.Is_Category("Fighter") and unit.Is_Category("Fighter") then
|
||||
|
||||
DebugMessage("%s -- Fighter shot by fighter, releasing unit from tf and attacking.", tostring(Script))
|
||||
tf.Release_Unit(unit)
|
||||
unit.Activate_Ability("SPOILER_LOCK", false)
|
||||
if not unit.Activate_Ability("BUZZ_DROIDS", attacker) then
|
||||
unit.Attack_Target(attacker)
|
||||
end
|
||||
|
||||
-- Default handling for a dying unit in both space and land modes.
|
||||
-- Is this unit not fodder AND do we have low health AND (we have a bad face off OR we're rapidly being killed for any reason)
|
||||
else
|
||||
|
||||
lib_time_till_dead = unit.Get_Time_Till_Dead()
|
||||
lib_attacker_is_good_vs_me = attacker.Is_Good_Against(unit)
|
||||
lib_i_am_good_vs_attacker = unit.Is_Good_Against(attacker)
|
||||
lib_current_health = unit.Get_Hull()
|
||||
lib_is_hero = unit.Get_Type().Is_Hero()
|
||||
lib_is_fodder = unit.Has_Property("Fodder")
|
||||
|
||||
if not lib_i_am_good_vs_attacker then
|
||||
Try_Ability(unit, "DEPLOY_TROOPERS")
|
||||
end
|
||||
|
||||
if ((not lib_is_fodder) and lib_time_till_dead < 20) or
|
||||
((not lib_is_fodder) and lib_current_health < 0.2) or
|
||||
(lib_is_hero and lib_current_health < 0.6) or
|
||||
(lib_current_health < 0.7 and lib_attacker_is_good_vs_me) or
|
||||
(lib_current_health < 0.4 and not lib_i_am_good_vs_attacker) then
|
||||
|
||||
--Certain factions have no self-preservation
|
||||
lib_faction_name = unit.Get_Owner().Get_Faction_Name()
|
||||
if lib_faction_name == "PIRATES" or lib_faction_name == "HUTTS" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Turn off any abilities that would hinder self-preservation
|
||||
unit.Activate_Ability("Power_To_Weapons", false)
|
||||
|
||||
-- Try to find the nearest healing structure appropriate for this unit
|
||||
lib_healer_property_flag = Get_Special_Healer_Property_Flag(unit)
|
||||
if not lib_healer_property_flag then
|
||||
if unit.Is_Category("Infantry") then
|
||||
lib_healer_property_flag = "HealsInfantry"
|
||||
elseif unit.Is_Category("Vehicle") then
|
||||
lib_healer_property_flag = "HealsVehicles"
|
||||
end
|
||||
end
|
||||
|
||||
if lib_healer_property_flag then
|
||||
healer = Find_Nearest(unit, lib_healer_property_flag, PlayerObject, true)
|
||||
end
|
||||
|
||||
lib_should_release = lib_attacker_is_good_vs_me or lib_is_hero or (lib_current_health < 0.33)
|
||||
|
||||
-- Try to heal if we have a healer
|
||||
if healer then
|
||||
GoHeal(tf, unit, healer, lib_should_release)
|
||||
end
|
||||
|
||||
if not lib_is_fodder then
|
||||
-- Try to find a protected kiting location
|
||||
friendly = Find_Nearest(unit, PlayerObject, true)
|
||||
xfire_pos = Get_Most_Defended_Position(unit, PlayerObject)
|
||||
if xfire_pos then
|
||||
kite_pos = Project_By_Unit_Range(attacker, xfire_pos)
|
||||
elseif TestValid(friendly) then
|
||||
DebugMessage("Failed to find a Most Defended Position, using position of nearby friendly.")
|
||||
kite_pos = Project_By_Unit_Range(attacker, friendly)
|
||||
else
|
||||
kite_pos = Project_By_Unit_Range(attacker, unit)
|
||||
end
|
||||
|
||||
GoKite(tf, unit, kite_pos, lib_should_release)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Default_Original_Target_Destroyed()
|
||||
--DebugMessage("%s -- Original target destroyed. Aborting.", tostring(Script))
|
||||
Attacking = false
|
||||
--ScriptExit() Some plans now have behaviors to occur after this event.
|
||||
end
|
||||
|
||||
function Default_Current_Target_Destroyed(tf)
|
||||
--MessageBox("%s -- Current target destroyed. Aborting.", tostring(Script))
|
||||
Attacking = false
|
||||
|
||||
-- Turn off some unending abilities that might no longer be appropriate
|
||||
tf.Activate_Ability("SPREAD_OUT", false)
|
||||
|
||||
--ScriptExit() Some plans now have behaviors to occur after this event.
|
||||
end
|
||||
|
||||
function Default_Original_Target_Owner_Changed(tf, old_player, new_player)
|
||||
if InvasionActive == true then
|
||||
return
|
||||
end
|
||||
|
||||
DebugMessage("%s -- Original target ownership changed. Aborting.", tostring(Script))
|
||||
ScriptExit()
|
||||
end
|
||||
|
||||
function Default_Unit_Move_Finished(tf, unit)
|
||||
Try_Deploy_Garrison(unit, nil, 0.5)
|
||||
end
|
||||
|
||||
|
||||
function Should_Crush(unit, target)
|
||||
|
||||
-- don't crush in easy mode
|
||||
if (PlayerObject.Get_Difficulty() == "Easy") then
|
||||
return false
|
||||
end
|
||||
|
||||
-- don't try to crush again if already on a diversion
|
||||
if unit.Is_On_Diversion() then
|
||||
return false
|
||||
end
|
||||
|
||||
-- if the vehicle is good at it, the victim is infantry, and vulnerable to crushing
|
||||
if unit.Has_Property("GoodInfantryCrusher") and target.Is_Category("Infantry") then
|
||||
if target.Is_Ability_Active("SPREAD_OUT") then
|
||||
return true
|
||||
elseif GameRandom.Get_Float() > 0.8 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- if the vehicle can crush anything and is close enough
|
||||
if unit.Has_Property("IsSupercrusher") and (unit.Get_Distance(target) < 75) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function Default_Target_In_Range(tf, unit, target)
|
||||
--MessageBox("%s -- unit: Default_Target_In_Range for: %s.", tostring(Script), tostring(unit), tostring(target))
|
||||
|
||||
-- We'll assume that once the first unit within a task force is in range, the attack has begun.
|
||||
Attacking = true
|
||||
|
||||
-- Certain units like to try to crush other units, but we can't crush Rebel units that are spread out
|
||||
if Should_Crush(unit, target) then
|
||||
DebugMessage("%s -- Attempting to crush %s with %s", tostring(Script), tostring(target), tostring(unit))
|
||||
unit.Divert(Project_By_Unit_Range(unit, target))
|
||||
end
|
||||
|
||||
Try_Deploy_Garrison(unit, target, 0.5)
|
||||
|
||||
-- Turn various abilities that would be useful.
|
||||
-- The ability time-out or the plan ending will turn off the ability.
|
||||
Try_Ability(unit, "Power_To_Weapons")
|
||||
Try_Ability(unit, "SPREAD_OUT")
|
||||
Try_Ability(unit, "BARRAGE", target)
|
||||
Try_Ability(unit, "BUZZ_DROIDS", target)
|
||||
Try_Ability(unit, "FULL_SALVO")
|
||||
Try_Ability(unit, "BLAST")
|
||||
|
||||
if unit.Get_Hull() > 0.5 then
|
||||
Try_Ability(unit, "STIM_PACK")
|
||||
end
|
||||
|
||||
Try_Weapon_Switch(unit, target)
|
||||
|
||||
GlobalValue.Set(PlayerSpecificName(PlayerObject, "CONTACT_OCCURED"), 1.0)
|
||||
end
|
||||
|
||||
function Default_Hardpoint_Target_In_Range(tf, unit, target)
|
||||
DebugMessage("%s -- A hardpoint of %s can now fire on target %s.", tostring(Script), tostring(unit), tostring(attacker))
|
||||
end
|
||||
|
||||
function Default_No_Units_Remaining()
|
||||
DebugMessage("%s -- All units dead or non-buildable. Abandonning plan.", tostring(Script))
|
||||
ScriptExit()
|
||||
end
|
||||
|
||||
function Default_Unit_Diversion_Finished(tf, unit)
|
||||
|
||||
if TestValid(unit) then
|
||||
-- Turn off turbo, if we happened to be using it to assist in a divert (evasive maneuver).
|
||||
unit.Activate_Ability("Turbo", false)
|
||||
unit.Activate_Ability("SPOILER_LOCK", false)
|
||||
end
|
||||
end
|
||||
|
||||
-- This fires if the countdown was going and it is now refreshed or if you come out of a nebula
|
||||
function Default_Unit_Ability_Ready(tf, unit, ability)
|
||||
|
||||
--MessageBox("%s ready for %s", ability, tostring(unit))
|
||||
|
||||
-- Try to recover use of interrupted abilities.
|
||||
if lib_cancelled_abilities[unit] and lib_cancelled_abilities[unit][ability] then
|
||||
--MessageBox("%s-- attempting to recover use of %s", tostring(Script), ability)
|
||||
unit.Activate_Ability(ability, true)
|
||||
lib_cancelled_abilities[unit][ability] = false
|
||||
end
|
||||
end
|
||||
|
||||
-- An ability was interrupted before naturally finishing.
|
||||
function Default_Unit_Ability_Cancelled(tf, unit, ability)
|
||||
DebugMessage("%s -- Ability %s of %s has been cancelled!", tostring(Script), ability, tostring(unit))
|
||||
|
||||
-- Track certain abilities that get cancelled, so we can recover them later
|
||||
if IsAbilityAllowedToRecover(ability) then
|
||||
|
||||
-- make a new ability table for this unit, if one doesn't yet exist
|
||||
if not lib_cancelled_abilities[unit] then
|
||||
lib_cancelled_abilities[unit] = {}
|
||||
end
|
||||
|
||||
lib_cancelled_abilities[unit][ability] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- An ability finished naturally by its duration running out or by being turned off.
|
||||
function Default_Unit_Ability_Finished(tf, unit)
|
||||
--DebugMessage("%s -- An ability for %s has finished!", tostring(Script), ability, tostring(unit))
|
||||
end
|
||||
Reference in New Issue
Block a user