s1-scripts-dev/raw/maps/mp/_movers.gsc
2025-05-21 16:23:17 +02:00

1397 lines
34 KiB
Plaintext

#include maps\mp\_utility;
#include common_scripts\utility;
/*script_brushmodel_mover (1 0.25 0.5) ?
script_brushmodel_movers will move and/or rotate to script_struct targets using the move
parameters defined in script_parameters. Script_structs can target additional script
structs to create paths and loops. Move parameters can be overridden with
script_parameters on script structs.
--------------------------------------------------------------------------------
Call level thread maps\mp\_movers::main() before _load::main(); in your level script.
---------------------------------------------------------------------------
Valid parameters that can be included in script_parameters:
move_time: Time to move to target
accel_time: Time spent accelerating. accel_time+decel_time must be less then move_time.
decel_time: Time spent decelerating. accel_time+decel_time must be less then move_time.
move_speed: Move speed of the mover. Overrides move_time.
accel_frac: The faction of the total move time spent accelerating [0.0 to 1.0]
decel_frac: The faction of the total move time spent decelerating [0.0 to 1.0]
delay_time: Time the mover will wait before moving to the next position
wait_time: Time the mover will wait after reaching to it's position
delay_till: Wait till this level notify before moving to the next position
wait_till: Wait till this level notify after reaching position
usable: Sets the mover to usable, used in combination with delay_till_trigger
delay_till_trigger: Will not move till target till mover receives "trigger" notify
solid: Set the brush to solid or or not
script_params: Allows parameters to be defined/added through script. Use
maps\mp\_movers::script_mover_add_parameters("example_set", "move_speed=5;accel_frac=.1")
in the level script to create a named set of parameters. The named parameters can be
included by setting script_params=name_of_set
--------------------------------------------------------------------------------
Advanced Stuff:
-To set the "angles" of a mover have the mover target a script_struct with angles
set and script_noteworthy=origin. This helps when rotating to angles on targeted structs
-Script_models can be linked to the mover by having the mover target them and setting
script_notewothy=link
-Movers can target other movers. A mover will send "trigger" to its targeted movers when
it started moving. Targeted movers should have delay_till_trigger.
-Script_structs can also target movers and will trigger all targeted movers when a mover
arrives at the script_struct
-Move parameters can be randomized with this syntax: <param_name>=<min_value>,<max_value>;
-Move parameters can be set back to default with this syntax: <param_name>=default
-If a mover targets a trigger with script_noteworthy=use_trigger_link or
script_noteworthy=use_trigger that trigger will trigger the mover when triggered. use_trigger_link
will link the trigger to the mover and use_trigger will not.
-Entities targeted by the mover or mover goals can modified. The targeted entity needs script_noteworthy
set to <action_name>_on_<notify>. Example script_noteworthy=show_on_arrive or script_noteworthy=hide_on_arrive;connectpaths_on_arrive
Notifies:
"arrive": Fires action when mover arrives at a goal
"depart": Fires action when mover leaves a position
Actions:
"connectpaths": Calls connect paths on the entity. Entity needs to be DYNAMIC_PATH
"disconnectpaths": Calls disconnect paths on the entity. Entity needs to be DYNAMIC_PATH
"solid": Makes the entity solid (makes entity notSolid on map start)
"notsolid": Makes the entity NotSolid
"delete": Deletes the entity
"hide": Hides the entity
"show": Shows the entity (hides entity on map start)
"triggerhide": Hides the entity by placing it under the world
"triggershow": Shows the entity by moving it into the world (ent is moved under the world at startup)
-----------------------------------------------------------------
default:"script_parameters" "move_time=5;accel_time=0;decel_time=0"
*/
/*script_model_mover (1 0.25 0.5) (-16 -16 -16) (16 16 16)
script_model_movers will move and/or rotate to script_struct targets using the move
parameters defined in script_parameters. Script_structs can target additional script
structs to create paths and loops. Move parameters can be overridden with
script_parameters on script structs.
--------------------------------------------------------------------------------
Call level thread maps\mp\_movers::main() before _load::main(); in your level script.
---------------------------------------------------------------------------
Valid parameters that can be included in script_parameters:
move_time: Time to move to target
accel_time: Time spent accelerating. accel_time+decel_time must be less then move_time.
decel_time: Time spent decelerating. accel_time+decel_time must be less then move_time.
move_speed: Move speed of the mover. Overrides move_time.
accel_frac: The faction of the total move time spent accelerating [0.0 to 1.0]
decel_frac: The faction of the total move time spent decelerating [0.0 to 1.0]
delay_time: Time the mover will wait before moving to the next position
wait_time: Time the mover will wait after reaching to it's position
delay_till: Wait till this level notify before moving to the next position
wait_till: Wait till this level notify after reaching position
usable: Sets the mover to usable, used in combination with delay_till_trigger
delay_till_trigger: Will not move till target till mover receives "trigger" notify
script_params: Allows parameters to be defined/added through script. Use
maps\mp\_movers::script_mover_add_parameters("example_set", "move_speed=5;accel_frac=.1")
in the level script to create a named set of parameters. The named parameters can be
included by setting script_params=name_of_set
--------------------------------------------------------------------------------
Advanced Stuff:
-To set the "angles" of a mover have the mover target a script_struct with angles
set and script_noteworthy=origin. This helps when rotating to angles on targeted structs
-Script_models can be linked to the mover by having the mover target them and setting
script_notewothy=link
-Movers can target other movers. A mover will send "trigger" to its targeted movers when
it started moving. Targeted movers should have delay_till_trigger.
-Script_structs can also target movers and will trigger all targeted movers when a mover
arrives at the script_struct
-Move parameters can be randomized with this syntax: <param_name>=<min_value>,<max_value>;
-If a mover targets a trigger with script_noteworthy=use_trigger_link or
script_noteworthy=use_trigger that trigger will trigger the mover when triggered. use_trigger_link
will link the trigger to the mover and use_trigger will not.
-Entities targeted by the mover or mover goals can modified. The targeted entity needs script_noteworthy
set to <action_name>_on_<notify>. Example script_noteworthy=show_on_arrive or script_noteworthy=hide_on_arrive;connectpaths_on_arrive
Notifies:
"arrive": Fires action when mover arrives at a goal
"depart": Fires action when mover leaves a position
Actions:
"connectpaths": Calls connect paths on the entity. Entity needs to be DYNAMIC_PATH
"disconnectpaths": Calls disconnect paths on the entity. Entity needs to be DYNAMIC_PATH
"solid": Makes the entity solid (makes entity notSolid on map start)
"notsolid": Makes the entity NotSolid
"delete": Deletes the entity
"hide": Hides the entity
"show": Shows the entity (hides entity on map start)
"triggerhide": Hides the entity by placing it under the world
"triggershow": Shows the entity by moving it into the world (ent is moved under the world at startup)
-----------------------------------------------------------------
default:"script_parameters" "move_time=5;accel_time=0;decel_time=0"
*/
SCRIPT_MOVER_NOTIFY_NAME = "script_mover_anim";
///////
// Movers
///////
main()
{
if( getDvar( "r_reflectionProbeGenerate" ) == "1" )
return;
level.script_mover_defaults = [];
level.script_mover_defaults["move_time"] = 5;
level.script_mover_defaults["accel_time"] = 0;
level.script_mover_defaults["decel_time"] = 0;
level.script_mover_defaults["wait_time"] = 0;
level.script_mover_defaults["delay_time"] = 0;
level.script_mover_defaults["usable"] = 0;
level.script_mover_defaults["hintstring"] = "activate";
script_mover_add_hintString("activate", &"MP_ACTIVATE_MOVER");
script_mover_add_parameters("none", "");
level.script_mover_named_goals = [];
level.script_mover_animations = [];
waitframe();
movers = [];
classnames = script_mover_classnames();
foreach(class in classnames)
{
movers = array_combine(movers, GetEntArray(class, "classname"));
}
array_thread(movers, ::script_mover_init);
}
script_mover_classnames()
{
return ["script_model_mover", "script_brushmodel_mover"];
}
script_mover_is_script_mover()
{
if(IsDefined(self.script_mover))
return self.script_mover;
classnames = script_mover_classnames();
foreach(class in classnames)
{
if(self.classname == class)
{
self.script_mover = true;
return true;
}
}
return false;
}
script_mover_add_hintString(name, hintString)
{
if(!IsDefined(level.script_mover_hintstrings))
level.script_mover_hintstrings = [];
level.script_mover_hintstrings[name] = hintString;
}
script_mover_add_parameters(name, parameters)
{
if(!IsDefined(level.script_mover_parameters))
level.script_mover_parameters = [];
level.script_mover_parameters[name] = parameters;
}
script_mover_add_animation(scene_name, animation_string, animation_ref, optional_type)
{
if(!IsDefined(level.script_mover_animations))
level.script_mover_animations = [];
if(!IsDefined(optional_type))
optional_type = "default";
if(!IsDefined(level.script_mover_animations[scene_name]))
level.script_mover_animations[scene_name] = [];
anim_info = spawnStruct();
anim_info.animname = animation_string;
anim_info.animref = animation_ref;
level.script_mover_animations[scene_name][optional_type] = anim_info;
}
script_mover_init()
{
self.script_mover = true;
self.moving = false;
self.origin_ent = self;
self.use_triggers = [];
self.linked_ents = [];
structs = [];
if(IsDefined(self.target))
structs = GetStructArray(self.target, "targetname");
foreach(target in structs)
{
if(!IsDefined(target.script_noteworthy))
continue;
switch(target.script_noteworthy)
{
case "origin":
if(!IsDefined(target.angles))
target.angles = (0,0,0);
self.origin_ent = spawn("script_model", target.origin);
self.origin_ent.angles = target.angles;
self.origin_ent SetModel("tag_origin");
self.origin_ent LinkTo(self);
break;
case "scripted_node":
case "scene_node":
if(!IsDefined(target.angles))
target.angles = (0,0,0);
self.scripted_node = target;
break;
default:
break;
}
}
ents = [];
if(IsDefined(self.target))
ents = GetEntArray(self.target, "targetname");
foreach(target in ents)
{
if(!IsDefined(target.script_noteworthy))
continue;
toks = StrTok(target.script_noteworthy, ";");
foreach(tok in toks)
{
switch(tok)
{
case "use_trigger_link":
target EnableLinkTo();
target LinkTo(self);
//Fallthrough
case "use_trigger":
target script_mover_parse_targets();
self thread script_mover_use_trigger(target);
self.use_triggers[self.use_triggers.size] = target;
break;
case "link":
target LinkTo(self);
self.linked_ents[self.linked_ents.size] = target;
break;
default:
break;
}
}
}
self thread script_mover_parse_targets();
self thread script_mover_init_move_parameters();
self thread script_mover_save_default_move_parameters();
self thread script_mover_set_defaults();
self thread script_mover_apply_move_parameters(self);
self thread script_mover_reset_init();
script_mover_start();
foreach(trigger in self.use_triggers)
{
self script_mover_set_usable(trigger, true);
}
self.script_mover_init = true;
self notify("script_mover_init");
}
script_mover_start()
{
if(self script_mover_is_animated())
{
self thread script_mover_animate();
}
else
{
self thread script_mover_move_to_target();
}
}
script_mover_reset_init()
{
self.mover_reset_origin = self.origin;
self.mover_reset_angles = self.angles;
}
script_mover_reset(unused)
{
self notify("mover_reset");
if(self script_mover_is_animated())
self ScriptModelClearAnim();
self.origin = self.mover_reset_origin;
self.angles = self.mover_reset_angles;
self notify("new_path");
waitframe();
self script_mover_start();
}
script_mover_use_trigger(trigger)
{
self endon("death");
while(1)
{
trigger waittill("trigger");
if(trigger.goals.size>0)
{
self notify("new_path");
self thread script_mover_move_to_target(trigger);
}
else
{
self notify("trigger");
}
}
}
script_mover_move_to_named_goal(goal_name)
{
if(IsDefined(level.script_mover_named_goals[goal_name]))
{
self notify("new_path");
self.goals = level.script_mover_named_goals[goal_name];
self thread script_mover_move_to_target();
}
}
anglesClamp180(angles)
{
return (AngleClamp180(angles[0]),AngleClamp180(angles[1]),AngleClamp180(angles[2]));
}
script_mover_parse_targets()
{
if(IsDefined(self.parsed) && self.parsed)
return;
self.parsed = true;
self.goals = [];
self.movers = [];
structs = [];
ents = [];
if(IsDefined(self.target))
{
structs = GetStructArray(self.target, "targetname");
ents = GetEntArray(self.target, "targetname");
}
for(i=0;i<structs.size;i++)
{
target = structs[i];
if(!IsDefined(target.script_noteworthy))
target.script_noteworthy = "goal"; //Assume goal this is a mover goal pos if not set
switch(target.script_noteworthy)
{
case "ignore":
if(IsDefined(target.target))
{
add_structs = GetStructArray(target.target, "targetname");
foreach(add in add_structs)
{
structs[structs.size] = add;
}
}
break;
case "goal":
target script_mover_init_move_parameters();
target script_mover_parse_targets();
self.goals[self.goals.size] = target;
if(IsDefined(target.params["name"]))
{
if(!IsDefined(level.script_mover_named_goals[target.params["name"]]))
level.script_mover_named_goals[target.params["name"]] = [];
size = level.script_mover_named_goals[target.params["name"]].size;
level.script_mover_named_goals[target.params["name"]][size] = target;
}
break;
default:
break;
}
}
foreach(ent in ents)
{
if(ent script_mover_is_script_mover())
{
self.movers[self.movers.size] = ent;
}
self thread script_mover_parse_ent( ent );
}
}
script_mover_parse_ent( ent )
{
if(!IsDefined(ent.script_noteworthy))
return;
if( ent script_mover_is_script_mover() && !IsDefined(ent.script_mover_init) )
{
ent waittill("script_mover_init");
}
notes = StrTok(ent.script_noteworthy, ";");
foreach(note in notes)
{
toks = StrTok(note, "_");
if(toks.size<3 || toks[1] != "on")
continue;
action = ToLower(toks[0]);
action_notify = toks[2]; //arrive or depart
for(i=3; i<toks.size; i++)
{
action_notify = action_notify + "_" + toks[i];
}
switch(action)
{
case "connectpaths":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_connectpaths, ::script_mover_disconnectpaths);
break;
case "disconnectpaths":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_disconnectpaths, ::script_mover_connectpaths);
break;
case "solid":
ent NotSolid();
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_solid, ::script_mover_notsolid);
break;
case "notsolid":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_notsolid, ::script_mover_solid);
break;
case "delete":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_delete);
break;
case "hide":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_hide, ::script_mover_show);
break;
case "show":
ent Hide();
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_show, ::script_mover_hide);
break;
case "triggerhide":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_trigger_off, ::script_mover_trigger_on);
break;
case "triggershow":
ent trigger_off();
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_trigger_on, ::script_mover_trigger_off);
break;
case "trigger":
self thread script_mover_func_on_notify(ent, action_notify, ::script_mover_trigger, ::script_mover_reset);
break;
default:
break;
}
}
}
script_mover_trigger_off(mover)
{
self DontInterpolate();
self trigger_off();
}
script_mover_trigger_on(mover)
{
self DontInterpolate();
self trigger_on();
}
script_mover_notify(mover, note)
{
mover notify(note);
}
script_mover_levelnotify(mover, note)
{
level notify(note);
}
script_mover_connectpaths(mover)
{
self ConnectPaths();
}
script_mover_disconnectpaths(mover)
{
self DisconnectPaths(mover);
}
script_mover_solid(mover)
{
self solid();
}
script_mover_notsolid(mover)
{
self NotSolid();
}
script_mover_delete(mover)
{
self delete();
}
script_mover_hide(mover)
{
self Hide();
}
script_mover_show(mover)
{
self show();
}
script_mover_trigger(mover)
{
self notify("trigger");
}
script_mover_func_on_notify(ent, note, func, reset_func)
{
self endon("death");
ent endon("death");
while(1)
{
self waittill(note, mover);
ent [[func]](mover);
if(IsDefined(reset_func) && IsDefined(mover))
{
mover script_mover_watch_for_reset(ent, reset_func);
}
else
{
break;
}
}
}
//childthread of script_mover_move_to_target
script_mover_update_paths()
{
dynamic_path_ents = [];
if(self script_mover_is_dynamic_path())
dynamic_path_ents[dynamic_path_ents.size] = self;
foreach(linked_ent in self.linked_ents)
{
if(linked_ent script_mover_is_dynamic_path())
dynamic_path_ents[dynamic_path_ents.size] = linked_ent;
}
if ( dynamic_path_ents.size == 0 )
{
return;
}
while(1)
{
foreach(ent in dynamic_path_ents)
{
ent script_mover_disconnectpaths();
}
self waittill("move_start");
foreach(ent in dynamic_path_ents)
{
ent script_mover_connectpaths();
}
self waittill("move_end");
}
}
script_mover_animate()
{
self childthread script_mover_update_paths();
scene_name = self.params["animation"];
if(IsDefined(level.script_mover_animations[scene_name]["idle"]))
script_mover_play_animation(level.script_mover_animations[scene_name]["idle"], false);
self script_mover_delay();
self notify("move_start");
self notify("start", self);
default_anim_info = level.script_mover_animations[scene_name]["default"];
if(IsDefined(default_anim_info))
{
script_mover_play_animation(default_anim_info, true);
self waittill("end");
}
self notify("move_end");
}
script_mover_play_animation(anim_info, process_notetracks)
{
self notify("play_animation");
if( process_notetracks )
self thread script_mover_handle_notetracks();
if(IsDefined(self.scripted_node))
{
self ScriptModelPlayAnimDeltaMotionFromPos(anim_info.animname, self.scripted_node.origin, self.scripted_node.angles, SCRIPT_MOVER_NOTIFY_NAME);
}
else
{
self ScriptModelPlayAnimDeltaMotion(anim_info.animname, SCRIPT_MOVER_NOTIFY_NAME);
}
}
script_mover_handle_notetracks()
{
self endon("play_animation");
self endon("mover_reset");
while(1)
{
self waittill(SCRIPT_MOVER_NOTIFY_NAME, note);
self notify(note, self);
}
}
script_mover_delay()
{
if(IsDefined(self.params["delay_till"]))
level waittill(self.params["delay_till"]);
if(IsDefined(self.params["delay_till_trigger"]) && self.params["delay_till_trigger"])
self waittill("trigger");
if(self.params["delay_time"]>0)
wait self.params["delay_time"];
}
script_mover_move_to_target(current)
{
self endon("death");
self endon("new_path");
self childthread script_mover_update_paths();
if(!IsDefined(current))
current = self;
while(current.goals.size!=0)
{
goal = random(current.goals);
mover = self;
mover script_mover_apply_move_parameters( goal );
mover script_mover_delay();
move_time = mover.params["move_time"];
accel_time = mover.params["accel_time"];
decel_time = mover.params["decel_time"];
is_moveTo = false;
is_rotateTo = false;
trans = TransformMove(goal.origin, goal.angles, self.origin_ent.origin, self.origin_ent.angles, self.origin, self.angles);
if(mover.origin != goal.origin)
{
if(IsDefined(mover.params["move_speed"]))
{
dist = distance(mover.origin, goal.origin);
move_time = dist/mover.params["move_speed"];
}
if(IsDefined(mover.params["accel_frac"]))
{
accel_time = mover.params["accel_frac"] * move_time;
}
if(IsDefined(mover.params["decel_frac"]))
{
decel_time = mover.params["decel_frac"] * move_time;
}
if(move_time<=0)
{
mover DontInterpolate();
mover.origin = trans["origin"];
}
else
{
mover MoveTo(trans["origin"], move_time, accel_time, decel_time );
}
is_moveTo = true;
}
if(anglesClamp180(trans["angles"]) != anglesClamp180(mover.angles))
{
if(move_time<=0)
{
mover DontInterpolate();
mover.angles = trans["angles"];
}
else
{
mover RotateTo(trans["angles"], move_time, accel_time, decel_time);
}
is_rotateTo = true;
}
//Trigger movers targeted my the mover
foreach ( targeted_mover in mover.movers )
{
targeted_mover notify("trigger");
self script_mover_watch_for_reset(targeted_mover, ::script_mover_reset);
}
mover notify("move_start");
current notify("depart", mover);
if( IsDefined(mover.params["name"]) )
{
notifyStr = "mover_depart_" + mover.params["name"];
mover notify(notifyStr);
level notify(notifyStr, mover);
}
mover script_mover_allow_usable(false);
if(move_time<=0)
{
//move instantly
}
else if(is_moveTo)
{
mover waittill("movedone");
}
else if(is_rotateTo)
{
mover waittill("rotatedone");
}
else
{
wait move_time;
}
mover notify("move_end");
goal notify("arrive", mover);
if( IsDefined(mover.params["name"]) )
{
notifyStr = "mover_arrive_" + mover.params["name"];
mover notify(notifyStr);
level notify(notifyStr, mover);
}
if(IsDefined(mover.params["solid"]))
{
if(mover.params["solid"])
mover solid();
else
mover notsolid();
}
//Trigger movers targeted my the goal
foreach ( targeted_mover in goal.movers )
{
targeted_mover notify("trigger");
self script_mover_watch_for_reset(targeted_mover, ::script_mover_reset);
}
if(IsDefined(mover.params["wait_till"]))
level waittill(mover.params["wait_till"]);
if(mover.params["wait_time"]>0)
wait mover.params["wait_time"];
mover script_mover_allow_usable(true);
current = goal;
}
}
script_mover_watch_for_reset(ent, func)
{
self thread script_mover_func_on_notify(ent, "mover_reset", func);
}
script_mover_init_move_parameters()
{
self.params = [];
if(!IsDefined(self.angles))
self.angles = (0,0,0);
self.angles = anglesClamp180(self.angles);
script_mover_parse_move_parameters(self.script_parameters);
}
script_mover_parse_move_parameters(parameters)
{
if(!IsDefined(parameters))
parameters = "";
params = StrTok(parameters, ";");
foreach(param in params)
{
toks = strtok(param,"=");
if(toks.size!=2)
continue;
if(toks[1]=="undefined" || toks[1]=="default")
{
//If default exist it will be set in script_mover_set_defaults
self.params[toks[0]] = "<undefined>";
continue;
}
switch(toks[0])
{
case "move_speed":
case "accel_frac":
case "decel_frac":
case "move_time":
case "accel_time":
case "decel_time":
case "wait_time":
case "delay_time":
self.params[toks[0]] = script_mover_parse_range(toks[1]);
break;
case "wait_till":
case "delay_till":
case "name":
case "hintstring":
case "animation":
self.params[toks[0]] = toks[1];
break;
case "usable":
case "delay_till_trigger":
case "solid":
self.params[toks[0]] = int(toks[1]);
break;
case "script_params":
param_name = toks[1];
additional_params = level.script_mover_parameters[param_name];
if(IsDefined(additional_params))
{
script_mover_parse_move_parameters(additional_params);
}
break;
default:
break;
}
}
}
script_mover_parse_range(str)
{
value = 0;
toks = strtok(str,",");
if(toks.size==1)
{
value = float(toks[0]);
}
else if(toks.size==2)
{
minValue = float(toks[0]);
maxValue = float(toks[1]);
if(minValue>=maxValue)
{
value = minValue;
}
else
{
value = RandomFloatRange(minValue,maxValue);
}
}
return value;
}
//to = self
script_mover_apply_move_parameters(from)
{
foreach(key, value in from.params)
{
script_mover_set_param(key, value);
}
script_mover_set_defaults();
}
script_mover_set_param(param_name, value)
{
if(!IsDefined(param_name))
return;
if(param_name=="usable" && IsDefined(value))
{
self script_mover_set_usable(self, value);
}
if(IsDefined(value) && isString(value) && value=="<undefined>")
{
value = undefined;
}
self.params[param_name] = value;
}
script_mover_allow_usable(usable)
{
if(self.params["usable"])
{
self script_mover_set_usable(self, usable);
}
foreach(trigger in self.use_triggers)
{
self script_mover_set_usable(trigger, usable);
}
}
script_mover_set_usable(use_ent,usable)
{
if(usable)
{
use_ent MakeUsable();
use_ent SetCursorHint("HINT_ACTIVATE");
use_ent SetHintString(level.script_mover_hintstrings[self.params["hintstring"]]);
}
else
{
use_ent MakeUnusable();
}
}
script_mover_save_default_move_parameters()
{
self.params_default = [];
foreach(key, value in self.params)
{
self.params_default[key] = value;
}
}
//Values in script_mover_defaults are assumed to always be defined
//this checks that they are.
script_mover_set_defaults()
{
if(IsDefined(self.params_default))
{
foreach(key, value in self.params_default)
{
if(!IsDefined(self.params[key]))
script_mover_set_param(key, value);
}
}
foreach(key, value in level.script_mover_defaults)
{
if(!IsDefined(self.params[key]))
script_mover_set_param(key, value);
}
}
script_mover_is_dynamic_path()
{
return (isDefined(self.spawnflags) && (self.spawnflags&1));
}
script_mover_is_animated()
{
return IsDefined(self.params["animation"]);
}
init()
{
level thread script_mover_connect_watch();
level thread script_mover_agent_spawn_watch();
}
script_mover_connect_watch()
{
while ( 1 )
{
level waittill( "connected", player );
player thread player_unresolved_collision_watch();
}
}
script_mover_agent_spawn_watch()
{
while ( 1 )
{
level waittill( "spawned_agent", agent );
agent thread player_unresolved_collision_watch();
}
}
player_unresolved_collision_watch()
{
self endon("disconnect");
if ( IsAgent( self ) )
{
self endon("death");
}
self.unresolved_collision_count = 0;
while(1)
{
self waittill( "unresolved_collision", mover );
self.unresolved_collision_count++;
self thread clear_unresolved_collision_count_next_frame();
unresolved_collision_notify_min = 3;
if(IsDefined(mover) && IsDefined(mover.unresolved_collision_notify_min))
unresolved_collision_notify_min = mover.unresolved_collision_notify_min;
if(self.unresolved_collision_count>=unresolved_collision_notify_min)
{
if(IsDefined(mover))
{
if(IsDefined( mover.unresolved_collision_func ))
{
mover [[mover.unresolved_collision_func]](self);
}
else if(IsDefined(mover.unresolved_collision_kill) && mover.unresolved_collision_kill)
{
mover unresolved_collision_owner_damage(self);
}
else
{
mover unresolved_collision_nearest_node(self);
}
}
else
{
unresolved_collision_nearest_node(self);
}
self.unresolved_collision_count = 0;
}
}
}
clear_unresolved_collision_count_next_frame()
{
self endon("unresolved_collision");
waitframe();
if(IsDefined(self))
self.unresolved_collision_count = 0;
}
unresolved_collision_owner_damage(player)
{
inflictor = self;
if(!IsDefined(inflictor.owner))
{
player maps\mp\_movers::mover_suicide();
return;
}
canInflictorOwnerDamagePlayer = false;
if( level.teambased )
{
if( IsDefined( inflictor.owner.team ) && inflictor.owner.team != player.team )
canInflictorOwnerDamagePlayer = true;
}
else
{
if(player != inflictor.owner)
canInflictorOwnerDamagePlayer = true;
}
if(!canInflictorOwnerDamagePlayer)
{
player maps\mp\_movers::mover_suicide();
return;
}
damage_ammount = 1000; //Kill
if(IsDefined(inflictor.unresolved_collision_damage))
damage_ammount = inflictor.unresolved_collision_damage;
player DoDamage( damage_ammount, inflictor.origin, inflictor.owner, inflictor, "MOD_CRUSH" );
}
unresolved_collision_nearest_node(player, bAllowSuicide)
{
nodes = self.unresolved_collision_nodes;
if(IsDefined(nodes))
{
nodes = SortByDistance(nodes, player.origin);
}
else
{
nodes = GetNodesInRadius( player.origin, 300, 0, 200 ); //Sorted version sorts by 2d dist, we need 3d
nodes = SortByDistance(nodes, player.origin);
}
avoid_telefrag_offset = (0,0,-100);
player CancelMantle();
player DontInterpolate();
player SetOrigin(player.origin + avoid_telefrag_offset);
for(i=0; i<nodes.size; i++)
{
check_node = nodes[i];
// if( check_node NodeIsDisconnected())
// continue;
org = check_node.origin;
if(!CanSpawn(org))
continue;
if(PositionWouldTelefrag(org))
continue;
if(player GetStance() == "prone")
player Setstance("crouch");
player SetOrigin( org );
return;
}
player SetOrigin(player.origin - avoid_telefrag_offset);
if( !IsDefined(bAllowSuicide) )
bAllowSuicide = true;
// no nodes found, fall back on suicide
if( bAllowSuicide )
{
player mover_suicide();
}
}
unresolved_collision_void(player)
{
}
mover_suicide()
{
if( IsDefined(level.isHorde) && !IsAgent( self ) )
{
return;
}
self _suicide();
}
//*******************************************************************
// *
// *
//*******************************************************************
player_pushed_kill( min_mph ) //self == mover
{
self endon("death");
self endon("stop_player_pushed_kill");
while( 1 )
{
self waittill( "player_pushed", player, platformMPH );
if ( isPlayer( player ) || isAgent( player ) )
{
mph = Length(platformMPH);
if ( mph >= min_mph )
{
self unresolved_collision_owner_damage(player);
}
}
}
}
stop_player_pushed_kill()
{
self notify("stop_player_pushed_kill");
}
//*******************************************************************
// *
// *
//*******************************************************************
notify_moving_platform_invalid()
{
children = self GetLinkedChildren( false );
if ( !IsDefined( children ) )
{
return;
}
foreach ( child in children )
{
if( IsDefined(child.no_moving_platfrom_unlink) && child.no_moving_platfrom_unlink )
continue;
child unlink();
child notify( "invalid_parent", self );
}
}
process_moving_platform_death( data, platform )
{
if(IsDefined(platform) && IsDefined(platform.no_moving_platfrom_death) && platform.no_moving_platfrom_death)
return;
if ( IsDefined( data.playDeathFx ) )
{
PlayFX( getfx( "airdrop_crate_destroy" ), self.origin );
}
if ( IsDefined( data.deathOverrideCallback ) )
{
self thread [[data.deathOverrideCallback]]( data );
}
else
{
self delete();
}
}
handle_moving_platform_touch( data )
{
while ( 1 )
{
self waittill( "touching_platform", platform );
if ( IsDefined( data.touchingPlatformValid ) && !self [[data.touchingPlatformValid]]( platform ) )
{
continue;
}
if ( IsDefined( data.validateAccurateTouching ) && data.validateAccurateTouching )
{
if ( !self IsTouching( platform ) )
{
wait( 0.05 );
continue;
}
}
self thread process_moving_platform_death( data, platform );
break;
}
}
handle_moving_platform_invalid( data )
{
self waittill( "invalid_parent", platform );
if ( IsDefined( data.invalidParentOverrideCallback ) )
{
self thread [[data.invalidParentOverrideCallback]]( data );
}
else
{
self thread process_moving_platform_death( data, platform );
}
}
// data: Spawned struct passed into handler.
// data.linkParent: Parent to link this entity to.
// data.endonString: String that will kill this handler when notified to entity.
// data.playDeathFx: Flag to play a generic death effect.
// data.deathOverrideCallback: Callback that will call instead of the automatic delete (ex. ims_override_death( platform ) ).
// data.invalidParentOverrideCallback: Callback that will call instead of the automatic invalid parent handler.
// data.validateAccurateTouching: If true, performs an extra IsTouching test on the touching platform before processing.
handle_moving_platforms( data )
{
self notify( "handle_moving_platforms" );
self endon( "handle_moving_platforms" );
level endon( "game_ended" );
self endon( "death" );
self endon( "stop_handling_moving_platforms" );
if ( !IsDefined( data ) )
{
data = SpawnStruct();
}
// Special endon string.
if ( IsDefined( data.endonString ) )
{
self endon( data.endonString );
}
if ( IsDefined( data.linkParent ) )
{
self linkto( data.linkParent );
}
childthread handle_moving_platform_touch( data );
childthread handle_moving_platform_invalid( data );
}
// Force kill this process without using data.endonString.
stop_handling_moving_platforms()
{
self notify( "stop_handling_moving_platforms" );
}
moving_platform_empty_func( data )
{
// Don't add anything.
}
//*******************************************************************
// *
// *
//*******************************************************************