876 lines
No EOL
26 KiB
Text
876 lines
No EOL
26 KiB
Text
#include maps\_anim;
|
|
#include maps\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\pel2_util;
|
|
#include maps\_vehicle_utility;
|
|
#include animscripts\utility;
|
|
#include animscripts\combat_utility;
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_bunker_group
|
|
// CALLED ON: level
|
|
// PURPOSE: After a group of bunker guards is spawned, waits until a player gets close enough or
|
|
// does explosive damage close enough to the bunker then causes a retreat.
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
do_bunker_group( bunker_name, new_bunker_name, event, groupid )
|
|
{
|
|
if( isDefined( groupid ) )
|
|
{
|
|
spawners = GetEntArray( groupid, "targetname" );
|
|
array_thread(spawners, ::add_spawn_function, maps\see2::setup_bunker_infantry);
|
|
|
|
trigger = getEnt( groupid, "target" );
|
|
if( isDefined( trigger ) )
|
|
{
|
|
trigger waittill( "trigger" );
|
|
wait( 1 );
|
|
}
|
|
}
|
|
group = get_living_ai_array( bunker_name+" guard", "script_noteworthy" );
|
|
goalNodes = getNodeArray( bunker_name+" retreat node", "script_noteworthy" );
|
|
damageTrigger = getEnt( bunker_name+" damage trigger", "script_noteworthy" );
|
|
smokeNodes = getEntArray( bunker_name+" smoke", "script_noteworthy" );
|
|
tankTrigger = getEnt( bunker_name+" tank trigger", "script_noteworthy" );
|
|
|
|
truck = getEnt( bunker_name+" truck", "script_noteworthy" );
|
|
|
|
for( i = 0; i < group.size; i++ )
|
|
{
|
|
if( isDefined( group[i] ) && group[i].classname == "actor_axis_ger_ber_wehr_reg_panzerschrek" )
|
|
{
|
|
group[i].maxsightdistsqrd = 3000*3000;
|
|
}
|
|
group[i].animname = "trench guy";
|
|
}
|
|
|
|
if( isDefined( damageTrigger ) )
|
|
{
|
|
damageTrigger thread maps\see2::inform_on_damage_trigger( "retreat "+bunker_name );
|
|
}
|
|
if( isDefined( tankTrigger ) )
|
|
{
|
|
tankTrigger thread maps\see2::inform_on_touch_trigger( "retreat "+bunker_name );
|
|
}
|
|
|
|
level waittill( "retreat "+bunker_name );
|
|
|
|
for( i = 0; i < smokeNodes.size; i++ )
|
|
{
|
|
if( isDefined( group[i] ) )
|
|
{
|
|
playfx( level._effect["retreat_smoke"], smokeNodes[i].origin );
|
|
wait( randomfloat( 0.5, 0.75 ) );
|
|
}
|
|
}
|
|
|
|
if( isDefined( truck ) )
|
|
{
|
|
movetrigger = getEnt( truck.script_noteworthy+" move trigger", "script_noteworthy" );
|
|
movetrigger notify( "trigger" );
|
|
}
|
|
|
|
group = get_living_ai_array( bunker_name+" guard", "script_noteworthy" );
|
|
|
|
//-- if I am not a panzerschreck guy, then I attempt to throw a panic grenade before I run
|
|
possible_tanks = GetEntArray( "script_vehicle", "classname" );
|
|
player_tanks = [];
|
|
for( i = 0; i < possible_tanks.size; i++ )
|
|
{
|
|
tank_owner = possible_tanks[i] GetVehicleOwner();
|
|
if( IsPlayer(tank_owner ) )
|
|
{
|
|
player_tanks[player_tanks.size] = possible_tanks[i];
|
|
}
|
|
}
|
|
|
|
|
|
notified = false;
|
|
for( i = 0; i < group.size && i < goalNodes.size; i++ )
|
|
{
|
|
if( isDefined( group[i] ) )
|
|
{
|
|
if( notified == false )
|
|
{
|
|
level notify( "retreaters", group[i] );
|
|
notified = true;
|
|
}
|
|
|
|
if( group[i].classname == "actor_axis_ger_ber_wehr_reg_kar98k" )
|
|
{
|
|
group[i].ignoreme = true;
|
|
group[i].ignoreall = true;
|
|
group[i] thread watch_for_grenade_throw_done( player_tanks, goalNodes[i] );
|
|
}
|
|
else
|
|
{
|
|
group[i] setGoalNode( goalNodes[i] );
|
|
group[i] thread do_panzerschreck_retreat();
|
|
}
|
|
group[i] thread maps\see2::do_generic_retreats();
|
|
wait( randomfloat( 0.7, 0.95 ) );
|
|
}
|
|
}
|
|
|
|
thread maps\see2::log_finished_event( event, 10 );
|
|
}
|
|
|
|
watch_for_grenade_throw_done(player_tanks, goal_node)
|
|
{
|
|
//-- if I am not a panzerschreck guy, then I attempt to throw a panic grenade before I run
|
|
if(player_tanks.size == 0)
|
|
{
|
|
return;
|
|
}
|
|
self.scripted_grenade_throw = true;
|
|
|
|
random_wait = RandomFloatRange(0.2, 1.5);
|
|
wait(random_wait);
|
|
|
|
my_target = player_tanks[0];
|
|
|
|
for( j=0 ; j<player_tanks.size; j++)
|
|
{
|
|
if( DistanceSquared(self.origin, my_target.origin) < DistanceSquared(self.origin, player_tanks[j].origin) )
|
|
{
|
|
my_target = player_tanks[j];
|
|
}
|
|
}
|
|
|
|
self maps\_grenade_toss::force_grenade_toss( my_target.origin, undefined, 3, undefined, undefined );
|
|
|
|
self setGoalNode( goal_node );
|
|
self.scripted_grenade_throw = undefined;
|
|
}
|
|
|
|
debug_line_on_damage()
|
|
{
|
|
while(1)
|
|
{
|
|
self waittill("damage", amount, attacker, direction, point, mod);
|
|
if(mod == "MOD_PROJECTILE")
|
|
{
|
|
Print3d( point, "***", (1, 0, 0), 1, 3, 3000 );
|
|
}
|
|
|
|
if(mod == "MOD_EXPLOSIVE")
|
|
{
|
|
Print3d( point, "***", (0, 0, 1), 1, 3, 3000 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_panzerschreck_retreat
|
|
// CALLED ON: a panzerschreck infantryman
|
|
// PURPOSE: makes the panzerscheck guy turn and fire every so often
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
do_panzerschreck_retreat()
|
|
{
|
|
self endon( "death" );
|
|
|
|
while( 1 )
|
|
{
|
|
self.ignoreall = true;
|
|
wait( randomintrange(6, 8) );
|
|
self.ignoreall = false;
|
|
wait( randomintrange( 6, 8 ) );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: wait_for_guard_tower_sploders
|
|
// CALLED ON: level
|
|
// PURPOSE: Spawns a drone for each guard tower and waits for the damage trigger for the
|
|
// script_exploder to go off
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
wait_for_guard_tower_sploders()
|
|
{
|
|
damage_triggers = GetEntArray( "guard tower damage trigger", "script_noteworthy" );
|
|
|
|
for( i = 0; i < damage_triggers.size; i++ )
|
|
{
|
|
drone_struct = getStruct( damage_triggers[i].target, "targetname" );
|
|
|
|
drone = maps\_drone::drone_scripted_spawn( "actor_axis_ger_ber_wehr_reg_kar98k", drone_struct );
|
|
damage_triggers[i].myDrone = drone;
|
|
|
|
damage_triggers[i] thread wait_for_single_sploder();
|
|
level.enemy_armor = array_add( level.enemy_armor, damage_triggers[i] );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: wait_for_single_sploder
|
|
// CALLED ON: a guard tower exploder trigger
|
|
// PURPOSE: waits until the tower is triggered, then removes it from the list of enemy targets
|
|
// and damages and eventually deletes the guard tower drone.
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
wait_for_single_sploder()
|
|
{
|
|
self waittill( "trigger", ent );
|
|
if( ent == get_players()[0] )
|
|
{
|
|
level notify( "destruction" );
|
|
}
|
|
self.destroyed = true;
|
|
if( !array_check_for_dupes( level.enemy_armor, self ) )
|
|
{
|
|
level.enemy_armor = array_remove( level.enemy_armor, self );
|
|
}
|
|
radiusdamage( self.origin, 150, 500, 500 );
|
|
|
|
if( isDefined( self.myDrone ) )
|
|
{
|
|
self.myDrone notify("no_drone_death_thread");
|
|
self.myDrone Delete();
|
|
//self.myDrone thread cleanup_drones();
|
|
}
|
|
|
|
if( IsPlayer( ent ) )
|
|
{
|
|
arcademode_assignpoints( "arcademode_score_banzai", ent );
|
|
}
|
|
|
|
level notify( "achievement_destroy_notify", "schreck_tower" );
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_fake_schrecks
|
|
// CALLED ON: level
|
|
// PURPOSE: threads all the tower triggers to get them to spawn fake panzerschreck fire
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
do_fake_schrecks()
|
|
{
|
|
tower_triggers = getEntArray( "guard tower damage trigger", "script_noteworthy" );
|
|
|
|
for( i = 0; i < tower_triggers.size; i++ )
|
|
{
|
|
tower_triggers[i] thread do_fake_schreck();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_fake_schreck
|
|
// CALLED ON: a guard tower exploder trigger
|
|
// PURPOSE: This will spawn panzerschreck fire from a struct targeted by the trigger every so
|
|
// often. If it is targeting multiple structs it will pick the best one. The fire will
|
|
// stop once the guard tower is destroyed
|
|
// ADDITIONS NEEDED:
|
|
/////////////////////////////////
|
|
do_fake_schreck()
|
|
{
|
|
self endon( "stop firing" );
|
|
self thread wait_for_my_sploder();
|
|
|
|
schrecks = getStructArray( self.target, "targetname" );
|
|
|
|
while( 1 )
|
|
{
|
|
if( !isDefined( level.player_tanks ) )
|
|
{
|
|
wait( 0.05 );
|
|
continue;
|
|
}
|
|
best_target = self maps\_vehicle::get_nearest_target( level.player_tanks );
|
|
for( i = 0; i < schrecks.size; i++ )
|
|
{
|
|
if( !check_in_arc( schrecks[i], best_target, 30 ) )
|
|
{
|
|
continue;
|
|
}
|
|
if( distancesquared( best_target.origin, schrecks[i].origin ) > (3500*3500) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
current_target = self maps\see2::request_target( best_target );
|
|
trace = bullettrace( schrecks[i].origin, current_target.origin, false, undefined );
|
|
if( trace["fraction"] < 0.95 )
|
|
{
|
|
continue;
|
|
}
|
|
dist = distance( current_target.origin, schrecks[i].origin );
|
|
level thread fire_schreck_at_pos( schrecks[i], current_target.origin, dist/2100 );
|
|
wait( 10 );
|
|
break;
|
|
}
|
|
wait( 0.05 );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: check_in_arc
|
|
// CALLED ON: a panzerschreck node
|
|
// PURPOSE: This checks to see if a player is in a specified arc for a given node (using its
|
|
// orientation as the basis for the arc orientation). Returns true if it is in the arc,
|
|
// false if it is not
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
check_in_arc( targeter, target, arc )
|
|
{
|
|
if( !isDefined( targeter ) || !isDefined( target ) || !isDefined( arc ) )
|
|
{
|
|
/#
|
|
iprintln( "COULD NOT FIRE SCHRECK, BAD DATA" );
|
|
#/
|
|
return false;
|
|
}
|
|
|
|
toVec = target.origin - targeter.origin;
|
|
toVec = ( toVec[0], toVec[1], 0 );
|
|
toAng = vectorToAngles( toVec );
|
|
if( abs(targeter.angles[1] - toAng[1]) < arc )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: fire_schreck_at_pos
|
|
// CALLED ON: level
|
|
// PURPOSE: This spawns a panzerschreck round and moves it from a start position to its target
|
|
// exploding when it reaches its target.
|
|
// ADDITIONS NEEDED: Make the damage and radius a tunable value
|
|
//
|
|
// Gavin's Changes: Added a damage entity that can be used so that the HUD points at the shrecks origin instead
|
|
// of using the world for the radius damage.
|
|
/////////////////////////////////
|
|
fire_schreck_at_pos( spawn_struct, target_pos, time )
|
|
{
|
|
// CODER_MOD : DSL - Make sure that the current snapshot isn't too crazy, before spawning one of these guys.
|
|
|
|
while( !OkToSpawn() )
|
|
{
|
|
wait( 0.1 );
|
|
}
|
|
|
|
shreck = spawn("script_model", spawn_struct.origin);
|
|
shreck.angles = vectortoangles( target_pos - spawn_struct.origin );
|
|
shreck setmodel("weapon_ger_panzershreck_rocket");
|
|
|
|
//-- Damage Entity
|
|
shreck_damage_ent = spawn("script_model", spawn_struct.origin);
|
|
|
|
dest = target_pos;
|
|
|
|
shreck moveTo( dest, time );
|
|
playFxOnTag( level._effect["rocket_trail"], shreck, "tag_fx" );
|
|
shreck playloopsound("rpg_rocket");
|
|
wait time;
|
|
|
|
shreck hide();
|
|
|
|
playfx( level._effect["shreck_explode"], shreck.origin );
|
|
|
|
shreck stoploopsound();
|
|
playSoundAtPosition("rpg_impact_boom", shreck.origin);
|
|
radiusdamage( shreck.origin, 256, 250, 250, shreck_damage_ent );
|
|
//earthquake( 0.5, 1.5, shreck.origin, 512 );
|
|
|
|
wait( 4 );
|
|
shreck Delete();
|
|
shreck_damage_ent Delete();
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: wait_for_my_sploder
|
|
// CALLED ON: an exploder trigger
|
|
// PURPOSE: Tells any fake panzerschrecks linked to a trigger to stop firing when the trigger is
|
|
// activated
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
wait_for_my_sploder()
|
|
{
|
|
self waittill( "trigger" );
|
|
self notify( "stop firing" );
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_flame_bunker
|
|
// CALLED ON: level
|
|
// PURPOSE: This generates fake panzerschreck fire from a flame bunker. It also generates drones
|
|
// to stand at the appropriate positions for flame deaths in case the bunker is flamed.
|
|
// drones are spawned based on the front_death, side_death and rear_death variables.
|
|
// Currently all do_flame_bunker calls have these set to false for drone limit reasons.
|
|
// The correct values are commented out next to these calls, so simply uncomment them to
|
|
// get proper behavior.
|
|
// ADDITIONS NEEDED: None, but need to work with animator to get anim positions synced.
|
|
//
|
|
// GAVIN CHANGE: the bunker now needs to be flamed for a certain period of time before it explodes
|
|
// and there is an added trigger to the bunker to trigger the model swap
|
|
//
|
|
/////////////////////////////////
|
|
do_flame_bunker( bunker_name, event, front_death, side_death, rear_death, kill_drones_at_spawn )
|
|
{
|
|
trigger = GetEnt( bunker_name+" damage trigger", "script_noteworthy" );
|
|
trigger.swap_trigger = GetEnt( bunker_name+" anim trigger", "script_noteworthy" );
|
|
|
|
tank_trigger = GetEnt( bunker_name+" tank trigger", "script_noteworthy" );
|
|
/#
|
|
tank_Trigger thread debug_line_on_damage();
|
|
#/
|
|
|
|
anim_nodes = GetStructArray( bunker_name+" anim node", "script_noteworthy" );
|
|
anim_node = anim_nodes[0];
|
|
front_guard = undefined;
|
|
side_guard = undefined;
|
|
rear_guard = undefined;
|
|
if( isDefined( front_death ) && front_death )
|
|
{
|
|
index = 1;//randomint(level.scr_anim["flame_bunker"]["front_death"].size);
|
|
curr_anim = level.scr_anim["flame_bunker"]["front_death"][index];
|
|
newOrigin = GetStartOrigin( anim_node.origin, anim_node.angles, curr_anim );
|
|
newAngles = GetStartAngles( anim_node.origin, anim_node.angles, curr_anim );
|
|
spawn_origin = spawnstruct();
|
|
spawn_origin.origin = newOrigin;
|
|
spawn_origin.angles = newAngles;
|
|
trigger.front_guard = maps\_drone::drone_scripted_spawn( "actor_axis_ger_ber_wehr_reg_kar98k", spawn_origin );
|
|
trigger.front_guard.flame_anim = curr_anim;
|
|
trigger.front_guard thread maps\_drone::drone_idle();
|
|
tank_trigger.front_guard = trigger.front_guard;
|
|
trigger.front_guard SetCanDamage( true );
|
|
|
|
if( IsDefined( kill_drones_at_spawn ) && kill_drones_at_spawn )
|
|
{
|
|
trigger.front_guard DoDamage( trigger.front_guard.health * 2, trigger.front_guard.origin, get_players()[0] );
|
|
}
|
|
}
|
|
|
|
if( isDefined( side_death ) && side_death )
|
|
{
|
|
index = 1;//randomint(level.scr_anim["flame_bunker"]["side_death"].size);
|
|
curr_anim = level.scr_anim["flame_bunker"]["side_death"][index];
|
|
newOrigin = GetStartOrigin( anim_node.origin, anim_node.angles, curr_anim );
|
|
newAngles = GetStartAngles( anim_node.origin, anim_node.angles, curr_anim );
|
|
spawn_origin = spawnstruct();
|
|
spawn_origin.origin = newOrigin;
|
|
spawn_origin.angles = newAngles;
|
|
trigger.side_guard = maps\_drone::drone_scripted_spawn( "actor_axis_ger_ber_wehr_reg_kar98k", spawn_origin );
|
|
trigger.side_guard.flame_anim = curr_anim;
|
|
trigger.side_guard thread maps\_drone::drone_idle();
|
|
tank_trigger.side_guard = trigger.side_guard;
|
|
trigger.side_guard SetCanDamage( true );
|
|
|
|
if( IsDefined( kill_drones_at_spawn ) && kill_drones_at_spawn )
|
|
{
|
|
trigger.side_guard DoDamage( trigger.side_guard.health * 2, trigger.side_guard.origin, get_players()[0] );
|
|
}
|
|
}
|
|
|
|
if( isDefined( rear_death ) && rear_death )
|
|
{
|
|
index = 1;//randomint(level.scr_anim["flame_bunker"]["rear_death"].size);
|
|
curr_anim = level.scr_anim["flame_bunker"]["rear_death"][index];
|
|
newOrigin = GetStartOrigin( anim_node.origin, anim_node.angles, curr_anim );
|
|
newAngles = GetStartAngles( anim_node.origin, anim_node.angles, curr_anim );
|
|
spawn_origin = spawnstruct();
|
|
spawn_origin.origin = newOrigin;
|
|
spawn_origin.angles = newAngles;
|
|
trigger.rear_guard = maps\_drone::drone_scripted_spawn( "actor_axis_ger_ber_wehr_reg_kar98k", spawn_origin );
|
|
trigger.rear_guard.flame_anim = curr_anim;
|
|
trigger.rear_guard thread maps\_drone::drone_idle();
|
|
tank_trigger.rear_guard = trigger.rear_guard;
|
|
trigger.rear_guard SetCanDamage( true );
|
|
|
|
if( IsDefined( kill_drones_at_spawn ) && kill_drones_at_spawn )
|
|
{
|
|
trigger.rear_guard DoDamage( trigger.rear_guard.health * 2, trigger.rear_guard.origin, get_players()[0] );
|
|
}
|
|
}
|
|
|
|
trigger thread do_fake_fb_schrecks( bunker_name );
|
|
trigger thread do_fb_effects();
|
|
|
|
tank_trigger thread do_flame_bunker_tank_damage( bunker_name );
|
|
trigger thread do_flame_bunker_flame_damage( bunker_name );
|
|
|
|
level notify( "event" );
|
|
|
|
}
|
|
|
|
do_flame_bunker_tank_damage(bunker_name)
|
|
{
|
|
level endon( bunker_name + "destroyed" );
|
|
|
|
trigger = self;
|
|
|
|
bunker_hit_max = 3;
|
|
bunker_hit_counter = 0;
|
|
|
|
while(1)
|
|
{
|
|
trigger waittill( "damage", damage, other, direction, origin, damage_type );
|
|
|
|
if(damage_type == "MOD_PROJECTILE")
|
|
{
|
|
bunker_hit_counter++;
|
|
|
|
if(bunker_hit_counter == bunker_hit_max)
|
|
{
|
|
//-- Destroy the bunker
|
|
level notify( bunker_name + "end_schrecks");
|
|
trigger thread do_secondary_fb_effects(bunker_name, true, other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
do_flame_bunker_flame_damage(bunker_name)
|
|
{
|
|
level endon( bunker_name + "destroyed" );
|
|
|
|
trigger = self;
|
|
|
|
while(1)
|
|
{
|
|
trigger waittill( "damage", damage, other, direction, origin, damage_type );
|
|
if( damage_type == "MOD_BURNED")
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( other == get_players()[0] )
|
|
{
|
|
level notify( "destruction" );
|
|
}
|
|
|
|
animNotify = "generic";
|
|
|
|
if( damage_type == "MOD_BURNED" )
|
|
{
|
|
flame_time = 0;
|
|
flame_time_threshold = 10;
|
|
|
|
if( isDefined( trigger.front_guard ) )
|
|
{
|
|
trigger.front_guard notify( "bunker flamed" );
|
|
trigger.front_guard DoDamage( trigger.front_guard.health * 2, trigger.front_guard.origin, get_players()[0]);
|
|
//trigger.front_guard animscripted( animNotify, trigger.front_guard.origin, trigger.front_guard.angles, trigger.front_guard.flame_anim );
|
|
//trigger.front_guard thread cleanup_drones();
|
|
}
|
|
if( isDefined( trigger.side_guard ) )
|
|
{
|
|
trigger.side_guard notify( "bunker flamed" );
|
|
trigger.side_guard DoDamage( trigger.side_guard.health * 2, trigger.side_guard.origin, get_players()[0]);
|
|
//trigger.side_guard animscripted( animNotify, trigger.side_guard.origin, trigger.side_guard.angles, trigger.side_guard.flame_anim );
|
|
//trigger.side_guard thread cleanup_drones();
|
|
}
|
|
if( isDefined( trigger.rear_guard ) )
|
|
{
|
|
trigger.rear_guard notify( "bunker flamed" );
|
|
trigger.rear_gaurd DoDamage( trigger.rear_guard.health * 2, trigger.rear_guard.origin, get_players()[0]);
|
|
//trigger.rear_guard animscripted( animNotify, trigger.rear_guard.origin, trigger.rear_guard.angles, trigger.rear_guard.flame_anim );
|
|
//trigger.rear_guard thread cleanup_drones();
|
|
}
|
|
|
|
while( flame_time < flame_time_threshold )
|
|
{
|
|
trigger waittill( "damage" );
|
|
flame_time++;
|
|
wait(0.05);
|
|
}
|
|
|
|
//wait( randomfloatrange( 2, 4 ) );
|
|
|
|
trigger thread do_secondary_fb_effects(bunker_name, undefined, other);
|
|
}
|
|
|
|
wait( 0.05 );
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: cleanup_drones
|
|
// CALLED ON: a drone
|
|
// PURPOSE: Waits until no players are looking at a drone then deletes it
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
cleanup_drones()
|
|
{
|
|
while( 1 )
|
|
{
|
|
visible = false;
|
|
for( i = 0; i < get_players().size; i++ )
|
|
{
|
|
myOrg = self.origin;
|
|
myOrg = ( myOrg[0], myOrg[1], 0 );
|
|
theirOrg = get_players()[i].origin;
|
|
theirOrg = ( theirOrg[0], theirOrg[1], 0 );
|
|
theirAng = get_players()[i].angles;
|
|
|
|
diff = VectorToAngles( myOrg - theirOrg ) - theirAng;
|
|
|
|
if( abs( diff[1] ) < 35 )
|
|
{
|
|
visible = true;
|
|
}
|
|
}
|
|
if( !visible )
|
|
{
|
|
break;
|
|
}
|
|
wait( 0.05 );
|
|
}
|
|
self notify( "delete" );
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_fake_fb_schrecks
|
|
// CALLED ON: a flame bunker trigger
|
|
// PURPOSE: This finds the best panzerschreck node to target the bunker's current target then
|
|
// fires a panzerschreck round at it.
|
|
// ADDITIONS NEEDED: Need to use check_in_arc similarly to the do_fake_schreck function
|
|
/////////////////////////////////
|
|
do_fake_fb_schrecks( bunker_name )
|
|
{
|
|
self endon( "trigger" );
|
|
level endon( bunker_name + "end_schrecks");
|
|
schreck_nodes = getStructArray( self.target, "targetname" );
|
|
|
|
while( 1 )
|
|
{
|
|
current_target = undefined;
|
|
target_array = get_players();
|
|
dist = 999999;
|
|
fire_node = -1;
|
|
for( i = 0; i < schreck_nodes.size; i++ )
|
|
{
|
|
for( j = 0; j < target_array.size; j++ )
|
|
{
|
|
dist = distanceSquared( schreck_nodes[i].origin, target_array[j].origin );
|
|
if( dist > (3500 * 3500) )
|
|
{
|
|
continue;
|
|
}
|
|
trace = bullettrace( schreck_nodes[i].origin, target_array[j].origin+(0,0,30), false, undefined );
|
|
if( trace["fraction"] > 0.95 )
|
|
{
|
|
current_target = target_array[j];
|
|
fire_node = i;
|
|
break;
|
|
}
|
|
}
|
|
if( isDefined( current_target ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if( isDefined( current_target ) )
|
|
{
|
|
dist = distance( schreck_nodes[fire_node].origin, current_target.origin );
|
|
level thread fire_schreck_at_pos( schreck_nodes[fire_node], current_target.origin+(randomfloatrange( -100, 100 ), randomfloatrange( -100, 100 ),30), dist/2100 );
|
|
wait( randomintrange( 10, 15 ) );
|
|
}
|
|
else
|
|
{
|
|
wait( 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_fb_effects
|
|
// CALLED ON: flame bunker trigger
|
|
// PURPOSE: Causes flame effects to play on the panzerscheck nodes when the bunker is flamed
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
do_fb_effects()
|
|
{
|
|
self.no_damage_timer = 0;
|
|
self.shutoff_time = 5;
|
|
exit_points = getStructArray( self.target, "targetname" );
|
|
|
|
while( 1 )
|
|
{
|
|
self waittill( "damage", damage, other, direction, origin, damage_type );
|
|
|
|
if( damage_type != "MOD_BURNED" )
|
|
{
|
|
continue;
|
|
}
|
|
self thread do_timer_resets();
|
|
self thread increment_damage_timer();
|
|
for( i = 0; i < exit_points.size; i++ )
|
|
{
|
|
playfx( level._effect["bunker_fire_start"], exit_points[i].origin, anglestoforward( exit_points[i].angles ) );
|
|
}
|
|
while( self.no_damage_timer < self.shutoff_time )
|
|
{
|
|
for( i = 0; i < exit_points.size; i++ )
|
|
{
|
|
playfx( level._effect["bunker_fire_out"], exit_points[i].origin, anglestoforward( exit_points[i].angles ) );
|
|
}
|
|
wait( 4.95 );
|
|
}
|
|
self notify( "kill_fx" );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_secondary_fb_effects
|
|
// CALLED ON: flame bunker trigger
|
|
// PURPOSE: This plays a series of flashes, followed by a massive explosion if a bunker is burned
|
|
// out. Happens first time only, and only with flame damage.
|
|
// ADDITIONS NEEDED: All these FX need a sound treatment
|
|
/////////////////////////////////
|
|
do_secondary_fb_effects( bunker_name, tank_kill, attacker )
|
|
{
|
|
if(IsDefined(tank_kill))
|
|
{
|
|
//-- Do anything special that needs to happen because a tank killed the bunker
|
|
if( isDefined( self.front_guard ) )
|
|
{
|
|
self.front_guard Delete();
|
|
}
|
|
if( isDefined( self.side_guard ) )
|
|
{
|
|
self.side_guard Delete();
|
|
}
|
|
if( isDefined( self.rear_guard ) )
|
|
{
|
|
self.rear_guard Delete();
|
|
}
|
|
}
|
|
|
|
playfx( level._effect["bunker_secondary_flash"], self.origin, anglestoforward( self.angles ) );
|
|
wait( 1 );
|
|
|
|
exploder_trigger = getEnt( bunker_name + " damage trigger exploder", "script_noteworthy" );
|
|
exploder_trigger notify( "trigger" );
|
|
|
|
damage_trigger = GetEnt( bunker_name + " damage trigger", "script_noteworthy");
|
|
exit_points = getStructArray( damage_trigger.target, "targetname" );
|
|
|
|
for( i = 0; i < exit_points.size; i++ )
|
|
{
|
|
playfx( level._effect["bunker_secondary_window"], exit_points[i].origin, anglestoforward( exit_points[i].angles ) );
|
|
}
|
|
|
|
wait(0.1); //-- give the fx time to populate
|
|
if(IsDefined(damage_trigger.swap_trigger))
|
|
{
|
|
damage_trigger.swap_trigger notify( "trigger" );
|
|
}
|
|
|
|
//-- Arcade points
|
|
player_hit_me = undefined;
|
|
if( IsPlayer( attacker ) )
|
|
{
|
|
player_hit_me = attacker;
|
|
}
|
|
else if( IsDefined(attacker.classname) && attacker.classname == "script_vehicle" )
|
|
{
|
|
veh_owner = attacker GetVehicleOwner();
|
|
|
|
if(IsDefined(veh_owner) && IsPlayer(veh_owner))
|
|
{
|
|
player_hit_me = attacker;
|
|
}
|
|
}
|
|
|
|
if(IsDefined(player_hit_me))
|
|
{
|
|
arcademode_assignpoints( "arcademode_score_generic500", player_hit_me );
|
|
}
|
|
|
|
level notify( "achievement_destroy_notify", "bunker" );
|
|
level notify( bunker_name + "destroyed" );
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: increment_damage_timer
|
|
// CALLED ON: flame bunker trigger
|
|
// PURPOSE: Used to determine when the window fx need to be refreshed if the player continues to
|
|
// flame a bunker by incrementing a counter
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
increment_damage_timer()
|
|
{
|
|
while( 1 )
|
|
{
|
|
self.no_damage_timer += 0.05;
|
|
if( self.no_damage_timer > self.shutoff_time )
|
|
{
|
|
return;
|
|
}
|
|
wait( 0.05 );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_timer_resets
|
|
// CALLED ON: flame bunker trigger
|
|
// PURPOSE: Resets the damage counter whenever a new damage event occurs
|
|
// ADDITIONS NEEDED: None
|
|
/////////////////////////////////
|
|
do_timer_resets()
|
|
{
|
|
self endon( "kill fx" );
|
|
while( 1 )
|
|
{
|
|
self waittill( "damage", damage, other, direction, origin, damage_type );
|
|
if( damage_type == "MOD_BURNED" )
|
|
{
|
|
self.no_damage_timer = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: setup_flame_bunker_guard
|
|
// CALLED ON: an AI
|
|
// PURPOSE: This sets the AI values for a flame bunker guard
|
|
// ADDITIONS NEEDED: This is deprecated, it should be pulled out, since
|
|
// flame bunker guards are going to be drones.
|
|
/////////////////////////////////
|
|
setup_flame_bunker_guard()
|
|
{
|
|
if( self.classname == "actor_axis_ger_ber_wehr_reg_panzerschrek" )
|
|
{
|
|
self.a.rockets = 200;
|
|
self.maxsightdistsqrd = 3000*3000;
|
|
self.a.no_weapon_switch = true;
|
|
self.ignoreall = true;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// FUNCTION: do_fortification_spawn
|
|
// CALLED ON: Level
|
|
// PURPOSE: Is used to gate the spawns of the drones that man the 88s, towers and flame bunkers
|
|
// ADDITIONS NEEDED:
|
|
// ADDED BY: G. Locke (8/11/08)
|
|
/////////////////////////////////
|
|
do_fortification_spawn( groupNum )
|
|
{
|
|
damage_triggers = GetEntArray( "guardtower group " + groupNum, "targetname" );
|
|
|
|
if(damage_triggers.size == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for( i = 0; i < damage_triggers.size; i++ )
|
|
{
|
|
drone_struct = getStruct( damage_triggers[i].target, "targetname" );
|
|
|
|
while( !OkToSpawn() )
|
|
{
|
|
wait(0.05);
|
|
}
|
|
|
|
drone = maps\_drone::drone_scripted_spawn( "actor_axis_ger_ber_wehr_reg_kar98k", drone_struct );
|
|
damage_triggers[i].myDrone = drone;
|
|
|
|
damage_triggers[i] thread wait_for_single_sploder();
|
|
level.enemy_armor = array_add( level.enemy_armor, damage_triggers[i] );
|
|
}
|
|
|
|
} |