1397 lines
34 KiB
Plaintext
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.
|
|
}
|
|
|
|
//*******************************************************************
|
|
// *
|
|
// *
|
|
//*******************************************************************
|