iw6-scripts-dev/maps/mp/_movable_cover.gsc
2024-12-11 11:28:08 +01:00

660 lines
15 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\gametypes\_hud_util;
///////
// movable_cover
///////
init()
{
if( getDvar( "r_reflectionProbeGenerate" ) == "1" )
return;
movable_cover_precache();
waitframe();
covers = GetEntArray("movable_cover", "targetname");
cover_proxy = getstructarray("movable_cover", "targetname");
foreach(proxy in cover_proxy)
{
if(IsDefined(proxy.target))
{
cover = GetEnt(proxy.target, "targetname");
if(IsDefined(cover))
{
covers[covers.size] = cover;
}
}
}
array_thread(covers, ::movable_cover_init);
}
movable_cover_precache()
{
level.movable_cover_use_icons = [];
level.movable_cover_use_icons["dumpster"] = "hud_icon_push";
level.movable_cover_move_sounds = [];
level.movable_cover_move_sounds["dumpster"]["start"] = "mp_dumpster_start";
level.movable_cover_move_sounds["dumpster"]["move"] = "mp_dumpster_mvmt_loop";
level.movable_cover_move_sounds["dumpster"]["stop"] = "mp_dumpster_end";
level.movable_cover_move_anim = [];
level.movable_cover_move_anim["dumpster"] = [];
level.movable_cover_move_anim["dumpster"]["move"] = "mp_lonestar_dumpster_jitter";
level.movable_cover_move_anim["dumpster"]["idle"] = "mp_lonestar_dumpster_jitter_idle";
level.movable_cover_default_parameters = [];
level.movable_cover_default_parameters["dumpster"] = "goal_radius=1;max_speed=80;accel_time=.8;decel_time=.8;stances=crouch,stand";
foreach(move_anim_type in level.movable_cover_move_anim)
{
foreach(move_anim in move_anim_type)
{
PrecacheMpAnim(move_anim);
}
}
}
movable_cover_init()
{
self.moving = false;
self.stay = false;
self.updatePaths = self.spawnflags & 1;
self.movable_type = "default";
if(IsDefined(self.script_noteworthy))
self.movable_type = self.script_noteworthy;
self movable_cover_parse_parameters();
//Find End points
end_points = [];
links = self get_links();
foreach(link in links)
{
point = getstruct(link, "script_linkname");
if(IsDefined(point) && IsDefined(point.script_label))
{
point.auto = IsDefined(point.script_parameters) && point.script_parameters=="auto";
point.stay = IsDefined(point.script_parameters) && point.script_parameters=="stay";
end_points[point.script_label] = point;
}
}
targets = [];
if(IsDefined(self.target))
{
structs = GetStructArray(self.target, "targetname");
ents = GetEntArray(self.target, "targetname");
targets = array_combine(structs, ents);
}
link_to_ent = self;
link_to_tag = undefined;
if(IsDefined(level.movable_cover_move_anim[self.movable_type]))
{
self.animate_ent = spawn("script_model", self.origin);
self.animate_ent SetModel("generic_prop_raven");
self.animate_ent.angles = self.angles;
self.animate_ent linkTo(self);
link_to_ent = self.animate_ent;
link_to_tag = "j_prop_1";
}
self.linked_ents = [];
foreach(target in targets)
{
if(!IsDefined(target.script_noteworthy))
continue;
switch(target.script_noteworthy)
{
case "move_trigger":
if(!IsDefined(target.script_label) || !IsDefined(end_points[target.script_label]))
continue;
target EnableLinkTo();
target LinkTo(self);
self thread movable_cover_trigger(target, end_points[target.script_label]);
self thread movable_cover_update_use_icon(target, end_points[target.script_label]);
break;
case "link":
self.linked_ents[self.linked_ents.size] = target;
break;
case "angels":
if(IsDefined(target.angles) && IsDefined(self.animate_ent))
self.animate_ent.angles = target.angles;
break;
case "mantlebrush":
self.linked_ents[self.linked_ents.size] = target;
//self thread movable_cover_mantlebrush_think( target );
break;
default:
break;
}
}
//link after to make sure the angels on animate_ent is set
foreach(ent in self.linked_ents)
{
if(IsDefined(link_to_tag))
{
ent LinkTo(link_to_ent, link_to_tag);
}
else
{
ent LinkTo(link_to_ent);
}
}
//Traversals
all_nodes = self getLinknameNodes();
self.traverse_nodes = [];
foreach(node in all_nodes)
{
if(!IsDefined(node.type))
continue;
node.node_type = node.script_noteworthy;
if(!IsDefined(node.node_type))
node.node_type = "closest";
node_type_valid = false;
switch(node.node_type)
{
case "closest":
node_type_valid= true;
break;
case "radius":
case "radius3d": //fallthrough
case "radius2d": //fallthrough
if(IsDefined(node.target))
{
target = getstruct(node.target, "targetname");
if(IsDefined(target) && IsDefined(target.radius))
{
node.test_origin = target.origin;
node.test_radius = target.radius;
node_type_valid= true;
}
}
break;
default:
node_type_valid = false;
break;
}
if(!node_type_valid)
continue;
if(node.type == "Begin" || node.type == "End")
{
if(node.type == "Begin")
{
node.connected_nodes = GetNodeArray(node.target, "targetname");
}
else //"End"
{
node.connected_nodes = GetNodeArray(node.targetname, "target");
}
//Disconnect all conenctions to start
foreach(connected_node in node.connected_nodes)
{
DisconnectNodePair(node, connected_node);
}
self.traverse_nodes[self.traverse_nodes.size] = node;
}
}
self movable_cover_connect_traversals(); //Reconnect the closest
}
movable_cover_set_user(user, trigger)
{
if(!IsDefined(self.user) && IsDefined(user))
self notify("new_user");
else if(IsDefined(self.user) && IsDefined(user) && self.user!=user)
self notify("new_user");
else if(IsDefined(self.user) && !IsDefined(user))
self notify("clear_user");
self.user = user;
self.user_trigger= trigger;
}
movable_cover_update_use_icon(trigger, move_to)
{
if(!IsDefined(level.movable_cover_use_icons[self.movable_type]))
return;
while( !IsDefined( level.players ) )
{
waitframe();
continue;
}
show_dist=100;
show_dist_sqr = show_dist*show_dist;
ent_num = trigger GetEntityNumber();
trigger_name = "trigger_" + ent_num;
while(1)
{
foreach(player in level.players)
{
if(!IsDefined(player.movable_cover_huds))
player.movable_cover_huds = [];
dist_sqr = DistanceSquared(player.origin+(0,0,30), trigger.origin);
if(dist_sqr<=show_dist_sqr && !self movable_cover_at_goal(move_to.origin))
{
if(!IsDefined(player.movable_cover_huds[trigger_name]))
{
player.movable_cover_huds[trigger_name] = movable_cover_use_icon(player, trigger);
player.movable_cover_huds[trigger_name].alpha = 0;
}
player.movable_cover_huds[trigger_name] notify("stop_fade");
player.movable_cover_huds[trigger_name] thread movable_cover_fade_in_use_icon();
}
else
{
if(IsDefined(player.movable_cover_huds[trigger_name]))
{
player.movable_cover_huds[trigger_name] thread movable_cover_fade_out_use_icon();
}
}
}
wait .05;
}
}
movable_cover_fade_in_use_icon()
{
self endon("death");
if(self.alpha == 1)
return;
self FadeOverTime(.5);
self.alpha = 1;
}
movable_cover_fade_out_use_icon()
{
self endon("death");
self endon("stop_fade");
if(self.alpha == 0)
return;
time = .5;
self FadeOverTime(time);
self.alpha = 0;
wait time;
self Destroy();
}
movable_cover_use_icon(player, ent)
{
icon = player createIcon( level.movable_cover_use_icons[self.movable_type], 16, 16 );
icon setWayPoint( true, false );
icon SetTargetEnt(ent);
icon.fading = false;
return icon;
}
movable_cover_parse_parameters()
{
//Init Delfaults
self.goal_radius = 1;
self.max_speed = 50;
self.accel_time = 1;
self.decel_time = 1;
self.requires_push = 1;
self.start_delay = .2;
self.stances = ["stand","crouch"];
if(!IsDefined(self.script_parameters))
self.script_parameters = "";
default_parameters = level.movable_cover_default_parameters[self.movable_type];
if(IsDefined(default_parameters))
self.script_parameters = default_parameters + self.script_parameters;
params = StrTok(self.script_parameters, ";");
foreach(param in params)
{
toks = strtok(param,"=");
if(toks.size!=2)
continue;
switch(toks[0])
{
case "goal_radius":
self.goal_radius = float(toks[1]);
self.goal_radius = max(1,self.goal_radius);
break;
case "max_speed":
self.max_speed = float(toks[1]);
break;
case "accel_time":
self.accel_time = float(toks[1]);
break;
case "decel_time":
self.decel_time = float(toks[1]);
self.decel_time = max(0.05,self.decel_time);
break;
case "stances":
self.stances = StrTok(toks[1], ",");
break;
case "requires_push":
self.requires_push = int(toks[1]);
break;
case "start_delay":
self.start_delay = float(toks[1]);
break;
default:
break;
}
}
}
movable_cover_trigger(trigger, move_to)
{
auto = move_to.auto;
stay = move_to.stay;
while(1)
{
player=undefined;
if(auto && !self.stay)
{
waitframe();
if(IsDefined(self.user) && self.user_trigger != trigger)
continue;
}
else
{
self movable_cover_set_user(undefined, undefined);
while(1)
{
trigger waittill("trigger", player);
if(isPlayer(player))
break;
}
self movable_cover_set_user(player, trigger);
}
if(self movable_cover_at_goal(move_to.origin))
continue;
move_dir = VectorNormalize(move_to.origin - self.origin);
if(!auto && !self movable_cover_move_delay(self.start_delay, player, trigger, move_dir) )
continue;
dist = Distance(self.origin, move_to.origin);
time = dist/self.max_speed;
if(auto && self.stay && !IsDefined(self.user))
continue;
if(self.moving)
continue;
if(self.updatePaths)
self ConnectPaths();
self movable_cover_disconnect_traversals();
self.moving = true;
self.stay = false;
self notify( "move_start" );
start_time = GetTime();
accel_time = min(time, self.accel_time);
if(auto)
accel_time = time;
start_sound = movable_cover_get_sound("start");
if(IsDefined(start_sound))
self PlaySound(start_sound);
move_sound = movable_cover_get_sound("move");
if(IsDefined(move_sound))
self PlayLoopSound(move_sound);
if(IsDefined(self.animate_ent) && IsDefined(level.movable_cover_move_anim[self.movable_type]["move"]))
{
self.animate_ent scriptmodelPlayanim(level.movable_cover_move_anim[self.movable_type]["move"]);
//self.animate_ent ScriptModelPlayAnimDeltaMotion(level.movable_cover_move_anim[self.movable_type]);
}
self MoveTo(move_to.origin, time, accel_time);
if(auto)
{
self movable_cover_wait_for_user_or_timeout(time);
}
else
{
while(movable_cover_is_pushed(player, trigger, move_dir) && !self movable_cover_at_goal(move_to.origin))
{
wait .05;
}
self movable_cover_set_user(undefined, undefined);
}
if(!self movable_cover_at_goal(move_to.origin))
{
current_speed_scale = movable_cover_calc_move_speed_scale((GetTime()-start_time)/1000, time, accel_time);
current_speed = self.max_speed * current_speed_scale;
dist = Distance(self.origin, move_to.origin);
stop_dist = dist;
if(current_speed>0)
{
stop_dist = min(dist,current_speed*self.decel_time);
}
time = (2*stop_dist)/self.max_speed;
self MoveTo(self.origin+(stop_dist*move_dir),time, 0, time);
wait time;
}
self StopLoopSound();
stop_sound = movable_cover_get_sound("stop");
if(IsDefined(stop_sound))
self PlaySound(stop_sound);
if(IsDefined(self.animate_ent) && IsDefined(level.movable_cover_move_anim[self.movable_type]["idle"]))
{
self.animate_ent scriptmodelPlayanim(level.movable_cover_move_anim[self.movable_type]["idle"]);
}
if(stay && self movable_cover_at_goal(move_to.origin))
{
self.stay = true;
}
if(self.updatePaths)
self DisconnectPaths();
self movable_cover_connect_traversals();
self.moving = false;
self notify( "move_end" );
}
}
movable_cover_connect_traversals()
{
self movable_cover_disconnect_traversals();
foreach(node in self.traverse_nodes)
{
switch(node.node_type)
{
case "closest":
node.connected_to = getClosest(node.origin, node.connected_nodes);
break;
case "radius":
case "radius3d": //fallthrough
dist = Distance(node.origin, node.test_origin);
if(dist<=node.test_radius)
node.connected_to = node.connected_nodes[0];
break;
case "radius2d":
dist2d = Distance2d(node.origin, node.test_origin);
if(dist2d<=node.test_radius)
node.connected_to = node.connected_nodes[0];
break;
default:
break;
}
if(IsDefined(node.connected_to))
{
ConnectNodePair(node, node.connected_to);
}
}
}
movable_cover_disconnect_traversals()
{
foreach(node in self.traverse_nodes)
{
if(IsDefined(node.connected_to))
{
DisconnectNodePair(node, node.connected_to);
node.connected_to = undefined;
}
}
}
movable_cover_get_sound(type)
{
if(!IsDefined(level.movable_cover_move_sounds[self.movable_type]))
return undefined;
return level.movable_cover_move_sounds[self.movable_type][type];
}
movable_cover_wait_for_user_or_timeout(time)
{
self endon("new_user");
wait time;
}
movable_cover_calc_move_speed_scale(current_time, move_time, accel_time, decel_time)
{
if(!IsDefined(accel_time))
accel_time = 0;
if(!IsDefined(decel_time))
decel_time = 0;
if(current_time >= move_time || current_time <= 0)
{
return 0;
}
else if(current_time < accel_time)
{
return 1 - ((accel_time - current_time) / accel_time);
}
else if(current_time > (move_time - decel_time))
{
return 1 - ((current_time - (move_time - decel_time)) / decel_time);
}
else
{
return 1;
}
}
movable_cover_is_pushed(player, trigger, move_dir)
{
//We have the player check so that the trigger doesn't error out when a dog enters.
if( !IsDefined( player ) || !IsReallyAlive( player ) || !IsPlayer( player) )
return false;
if(!movable_cover_is_touched(trigger, player))
return false;
if(player IsMantling())
return false;
stance = player GetStance();
if(!array_contains(self.stances, stance))
return false;
if(self.requires_push)
{
player_move_dir = player GetNormalizedMovement();
player_move_dir = RotateVector(player_move_dir, -1*player.angles);
player_move_dir = VectorNormalize((player_move_dir[0], -1*player_move_dir[1], 0));
dot = VectorDot(move_dir, player_move_dir);
return dot>0.2;
}
else
{
return true;
}
}
movable_cover_is_touched(trigger, player)
{
return IsDefined( player ) && isReallyAlive( player ) && player IsTouching(trigger);
}
movable_cover_move_delay(delay, player, trigger, move_dir)
{
endTime = (delay*1000)+GetTime();
while(1)
{
if( !IsDefined( player ) || !isReallyAlive( player ) )
return false;
if(player IsMantling())
return false;
if(!movable_cover_is_pushed(player, trigger, move_dir))
return false;
if(self.moving)
return false;
if(getTime()>=endTime)
return true;
wait .05;
}
}
movable_cover_at_goal(goal)
{
distSqr = DistanceSquared(self.origin, goal);
return distSqr<=(self.goal_radius*self.goal_radius);
}
// Make movers unmantleable while moving - avoids animating into solid architecture
movable_cover_mantlebrush_think( mantlebrush )// self = mover
{
self endon("death");
while(1)
{
self waittill( "move_start" );
if ( IsDefined( mantlebrush ) )
{
mantlebrush.old_contents = mantlebrush SetContents( 0 );
mantlebrush Hide();
}
self waittill( "move_end" );
if ( IsDefined( mantlebrush ) )
{
mantlebrush Show();
mantlebrush SetContents( mantlebrush.old_contents );
}
}
}