IL-GSC/BO1/PC/ZM/maps/_contextual_melee.gsc
2024-02-18 17:32:07 -05:00

715 lines
21 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#using_animtree("generic_human");
setup()
{
if ( IsDefined( level.contextualMeleeFeature ) && !level.contextualMeleeFeature )
return;
level._melee = SpawnStruct();
level._CONTEXTUAL_MELEE_DIST = 70;
level._CONTEXTUAL_MELEE_DIST_SQ = level._CONTEXTUAL_MELEE_DIST
* level._CONTEXTUAL_MELEE_DIST;
level._CONTEXTUAL_MELEE_LERP_TIME = .3;
level._contextual_melee_print_hintstring = true;
level._contextual_melee_allow_fire_button = false;
PrecacheRumble("melee_garrote");
PrecacheModel("weapon_parabolic_knife");
setup_fx();
setup_info();
}
main(melee_id, set)
{
if (IsDefined(melee_id) && !IsString(melee_id) && !melee_id)
{
self notify("stop_contextual_melee");
return;
}
if (!IsDefined(self._melee))
{
self._melee = SpawnStruct();
}
if (!IsDefined(set) || set == "any")
{
self._melee.set = array_reverse(GetArrayKeys(level._melee.info));
self._melee.set = array_remove(self._melee.set, "scripted");
}
else if (IsString(set) || IsArray(set))
{
self._melee.set = set;
}
else
{
assertmsg("Contetual Melee set must be a string or an array of strings.");
}
self._melee.type = undefined;
self._melee.ai_context = undefined;
self._melee.player_context = undefined;
if (IsDefined(melee_id))
{
melee_info = StrTok(ToLower(melee_id), "_");
self._melee.type = melee_info[0];
if (IsDefined(melee_info[1]))
{
self._melee.ai_context = melee_info[1];
}
if (IsDefined(melee_info[2]))
{
self._melee.player_context = melee_info[2];
}
self remove_weapon(melee_id);
if (IsDefined(self._melee.ai_context))
{
self thread do_idle(self._melee.type, self._melee.ai_context);
}
}
self thread contextual_melee_thread();
}
remove_weapon(melee_id)
{
if (IsSubStr(melee_id, "garrote_sit") || IsSubStr(melee_id, "neckstab_crouch"))
{
self gun_remove();
}
}
get_context()
{
if (IsAI(self))
{
if (IsDefined(self._melee.ai_context))
{
return self._melee.ai_context;
}
else
{
return self.a.pose;
}
}
else if (IsPlayer(self))
{
return self GetStance();
}
else
{
assertmsg("_contextual_melee: trying to get context for unsupported entity type.");
}
}
waittill_melee()
{
while (true)
{
player = undefined;
while (!IsDefined(player))
{
wait .05;
if (!IsAlive(self))
{
return;
}
players = get_players();
for (i = 0; i < players.size; i++)
{
if (players[i] player_can_melee(self))
{
player = players[i];
break;
}
}
}
if (player player_interaction(self))
{
player notify("melee_attack", self);
self notify("melee_victim", player);
return player;
}
}
}
cancel_waittill_melee(guy)
{
guy waittill_any("stop_contextual_melee", "death");
player = get_players()[0];
player SetScriptHintString("");
self enable_weapon();
}
player_can_melee(guy)
{
info = get_potential_melee_info(guy);
if (IsDefined(info))
{
guy._melee.info = info;
dist = DistanceSquared(guy.origin, self.origin);
if (dist < level._CONTEXTUAL_MELEE_DIST_SQ)
{
looking_at = is_player_looking_at(guy GetTagOrigin("J_Neck"), .7, false);
if( isdefined(guy._melee_ignore_angle_override) )
{
return looking_at;
}
facing_same_way = (VectorDot(AnglesToForward(guy.angles), AnglesToForward(self GetPlayerAngles())) > 0.4);
return looking_at && facing_same_way;
}
}
return false;
}
get_potential_melee_info(guy)
{
info = [];
set = [];
if (IsArray(guy._melee.set))
{
set = guy._melee.set;
}
else
{
set[0] = guy._melee.set;
}
for (i = 0; i < set.size; i++)
{
if (IsDefined(guy._melee.type))
{
info = get_info_by_type(guy._melee.type, guy get_context(), self get_context(), set[i]);
}
else
{
info = get_info(self get_context(), guy get_context(), set[i]);
}
if (IsDefined(info) && info.size > 0)
{
return info;
}
}
}
player_interaction(guy)
{
self AllowMelee(false);
if( level._contextual_melee_print_hintstring )
{
self SetScriptHintString(&"SCRIPT_HINT_MELEE");
}
self thread cancel_waittill_melee(guy);
cancled = false;
if( level._contextual_melee_allow_fire_button )
{
while (!guy is_auto_melee() && !self MeleeButtonPressed() && !cancled && !self MeleeButtonPressed())
{
if (!self player_can_melee(guy) || !IsAlive(guy))
{
self enable_weapon();
cancled = true;
}
else
{
self notify("melee_in_position");
}
wait(0.05);
}
}
else
{
while (!guy is_auto_melee() && !self MeleeButtonPressed() && !cancled )
{
if (!self player_can_melee(guy) || !IsAlive(guy))
{
self enable_weapon();
cancled = true;
}
else
{
self notify("melee_in_position");
}
wait(0.05);
}
}
self SetScriptHintString("");
if (!cancled)
{
self disable_weapon();
}
return !cancled;
}
is_auto_melee()
{
return (is_true(self.automatic_contextual_melee));
}
disable_weapon()
{
self HideViewModel();
self DisableWeapons();
}
enable_weapon()
{
self ShowViewModel();
self EnableWeapons();
self AllowMelee(true);
}
get_alignment_object()
{
if(IsDefined(level._contextual_melee_align_obj))
{
return level._contextual_melee_align_obj;
}
else if (IsDefined(self.target))
{
obj = GetEnt(self.target, "targetname");
if( !IsDefined( obj ) )
{
obj = getstruct( self.target, "targetname" );
}
if (IsDefined(obj))
{
return obj;
}
}
return self;
}
contextual_melee_thread()
{
self notify("_contextual_melee_thread");
self endon("_contextual_melee_thread");
self endon("stop_contextual_melee");
if (self is_scripted_melee())
{
self waittill("start_scripted_melee", player);
self._melee.info = get_info_by_type(self._melee.type, "scripted", "scripted", "scripted");
player disable_weapon();
}
else
{
player = waittill_melee();
}
if (IsAlive(self) && IsDefined(player))
{
self thread do_contextual_melee(player);
}
}
is_scripted_melee()
{
return (IsDefined(self._melee.set) && IsString(self._melee.set) && (self._melee.set == "scripted"));
}
do_idle(type, ai_context)
{
self endon("stop_contextual_melee_idle");
if (is_valid_stance(ai_context))
{
self AllowedStances(ai_context);
}
else
{
set = self._melee.set;
if (IsArray(set))
{
set = set[0];
}
ai_idle = get_idle_anim(type, ai_context, set);
if (IsDefined(ai_idle))
{
self._melee.set = set;
self._contextual_melee_align_obj = get_alignment_object();
origin = self._contextual_melee_align_obj.origin;
angles = self._contextual_melee_align_obj.angles;
while (true)
{
self AnimScripted("contextual_melee_idle_anim", origin, angles, ai_idle);
self animscripts\shared::DoNoteTracks("contextual_melee_idle_anim");
}
}
}
}
get_idle_anim(type, ai_context, which_set)
{
info = get_info_set(which_set, true);
if (IsDefined(info[type]))
{
if (IsDefined(info[type][ai_context]))
{
info = random(info[type][ai_context]);
if (IsDefined(info["ai_idle"]))
{
return info["ai_idle"];
}
}
}
}
is_valid_stance(stance)
{
return (stance == "stand" || stance == "crouch" || stance == "prone");
}
do_contextual_melee(player)
{
info = self._melee.info;
player FreezeControls(true);
player notify( "do_contextual_melee" );
self notify( "do_contextual_melee" );
self stop_everything();
assertex(IsDefined(info) && (info.size > 0), "Invalid info array for melee.");
self._contextual_melee_align_obj = get_alignment_object();
if (does_melee_type_need_legs(info["type"]))
{
player spawn_player_model(self._contextual_melee_align_obj, info);
}
else
{
player spawn_player_hands(self._contextual_melee_align_obj, info);
}
player thread animate_player_hands(self, info);
self waittill("contextual_melee_start_anim");
self notify("stop_contextual_melee_idle");
self AnimScripted("contextual_melee_anim", self._contextual_melee_align_obj.origin, self._contextual_melee_align_obj.angles, info["ai"]);
self thread do_fx();
self animate_prop();
self thread contextual_melee_watch_for_anim_end();
self waittill_either("finish_contextual_melee", "death");
finish = true;
if (IsDefined(info["callback"]))
{
finish = player [[info["callback"]]](self);
}
else
{
player thread end_contextual_melee(self);
}
self notify("melee_done");
player notify("melee_done");
if (!is_false(finish))
{
player.player_hands Delete();
if (!IsAlive(self))
{
return;
}
if (IsDefined(info["ai_deathpose"]))
{
self.takedamage = false;
self death_notify_wrapper();
while (true)
{
self AnimScripted("contextual_melee_deathpose", self._contextual_melee_align_obj.origin, self._contextual_melee_align_obj.angles, info["ai_deathpose"]);
self animscripts\shared::DoNoteTracks("contextual_melee_deathpose");
}
}
}
}
stop_everything()
{
self notify("end_patrol");
self notify("_stealth_stop_stealth_logic");
self notify("_stealth_stop_corpse_logic");
self.ignoreall = true;
self.goalradius = 0;
self SetGoalPos(self.origin);
self Unlink();
self anim_stopAnimScripted();
}
contextual_melee_watch_for_anim_end()
{
self animscripts\shared::DoNoteTracks("contextual_melee_anim");
self notify("finish_contextual_melee");
}
contextual_melee_watch_for_victim_died()
{
self waittill("death");
self notify("finish_contextual_melee");
}
end_contextual_melee(victim)
{
level waittill_any_ents(victim, "death", self, "melee_done");
self Unlink();
self notify( "contextual_melee_complete" );
if (!is_false(level._contextual_melee_hack))
{
trace_start = self.origin + (0,0,100);
trace_end = self.origin + (0,0,-100);
player_trace = BulletTrace(trace_start, trace_end, false, victim);
self SetOrigin(player_trace["position"]);
}
self FreezeControls(false);
self enable_weapon();
}
setup_fx()
{
level._effect["neckstab_stand_blood"] = LoadFX("impacts/fx_melee_neck_stab");
level._effect["neckstab_crouch_blood"] = LoadFX("impacts/fx_melee_neck_stab_crouching");
level._effect["neckstab_stand_blood_left"] = LoadFX( "impacts/fx_melee_neck_stab_left" );
level._effect["hatchet_arm_blood"] = LoadFX( "maps/rebirth/fx_axe_to_the_arm" );
}
get_info_by_type(type, ai_context, player_context, which_set)
{
info = get_info_set(which_set, true);
if (IsDefined(info[type]))
{
if (IsDefined(info[type][ai_context]))
{
if (IsDefined(info[type][ai_context][player_context]))
{
return info[type][ai_context][player_context];
}
}
}
}
get_info(player_context, ai_context, which_set)
{
info = get_info_set(which_set);
if (IsDefined(info[player_context]))
{
if (IsDefined(info[player_context][ai_context]))
{
info = info[player_context][ai_context];
keys = GetArrayKeys(info);
type = keys[RandomInt(keys.size)];
info = info[type];
return info;
}
}
}
get_info_set(which_set, by_type)
{
if (!IsDefined(which_set))
{
which_set = "default";
}
if (is_true(by_type))
{
return level._melee.info_by_type[which_set];
}
else
{
return level._melee.info[which_set];
}
}
setup_info()
{
add_melee_sequence("default", "garrote", "stand", "stand", %int_contextual_melee_garrote,
%ai_contextual_melee_garrote);
add_melee_sequence("default", "garrote", "stand", "sit", %int_contextual_melee_garrotesit,
%ai_contextual_melee_garrotesit_death,
%ai_contextual_melee_garrotesit_idle,
%ai_contextual_melee_garrotesit_deathpose);
add_melee_sequence("default", "necksnap", "stand", "stand", %int_contextual_melee_necksnap,
%ai_contextual_melee_necksnap);
add_melee_sequence("default", "neckstab", "stand", "stand", %int_contextual_melee_neckstab,
%ai_contextual_melee_neckstab);
add_melee_sequence("default", "neckstab", "stand", "crouch",%int_contextual_melee_neckstabcrouch,
%ai_contextual_melee_neckstabcrouch_death,
%ai_contextual_melee_neckstabcrouch_idle);
add_melee_sequence("quick", "garrote", "stand", "stand", %int_contextual_melee_garrote_quick,
%ai_contextual_melee_garrote_quick);
add_melee_sequence("quick", "garrote", "stand", "sit", %int_contextual_melee_garrotesit_quick,
%ai_contextual_melee_garrotesit_death_quick,
%ai_contextual_melee_garrotesit_idle,
%ai_contextual_melee_garrotesit_deathpose);
add_melee_sequence("quick", "necksnap", "stand", "stand", %int_contextual_melee_necksnap_quick,
%ai_contextual_melee_necksnap_quick);
add_melee_sequence("quick", "neckstab", "stand", "stand", %int_contextual_melee_neckstab_quick,
%ai_contextual_melee_neckstab_quick);
add_melee_sequence("quick", "neckstab", "stand", "crouch", %int_contextual_melee_neckstabcrouch_quick,
%ai_contextual_melee_neckstabcrouch_death_quick,
%ai_contextual_melee_neckstabcrouch_idle);
add_melee_sequence("quick", "neckstab", "crouch", "stand", %int_contextual_melee_crouch_neckstab_quick,
%ai_contextual_melee_crouch_neckstab_quick);
add_melee_sequence("quick", "kneekick", "stand", "stand", %int_contextual_melee_kneekick_quick,
%ai_contextual_melee_kneekick_quick);
add_melee_sequence("quick", "elbowhit", "stand", "stand", %int_contextual_melee_elbow_hit_quick,
%ai_contextual_melee_elbow_hit_quick);
add_melee_sequence("quick", "judochop", "stand", "stand", %int_contextual_melee_judochop_quick,
%ai_contextual_melee_judochop_quick);
add_melee_sequence("quick", "headpunch", "stand", "stand", %int_contextual_melee_headpunch_quick,
%ai_contextual_melee_headpunch_quick);
level.scr_animtree[ "player_hands_contextual_melee" ] = #animtree;
level.scr_model[ "player_hands_contextual_melee" ] = level.player_interactive_hands;
level.scr_animtree[ "player_model_contextual_melee" ] = #animtree;
level.scr_model[ "player_model_contextual_melee" ] = level.player_interactive_model;
setup_props();
}
add_melee_sequence(set, type, player_context, ai_context, player_anim, ai_anim, ai_idle, ai_deathpose)
{
if (!IsDefined(level._melee.info))
{
level._melee.info = [];
}
level._melee.info[set][player_context][ai_context][type]["player"] = player_anim;
level._melee.info[set][player_context][ai_context][type]["ai"] = ai_anim;
level._melee.info[set][player_context][ai_context][type]["type"] = type;
if (IsDefined(ai_idle))
{
level._melee.info[set][player_context][ai_context][type]["ai_idle"] = ai_idle;
}
if (IsDefined(ai_deathpose))
{
level._melee.info[set][player_context][ai_context][type]["ai_deathpose"] = ai_deathpose;
}
if (!IsDefined(level._melee.info_by_type))
{
level._melee.info_by_type = [];
}
level._melee.info_by_type[set][type][ai_context][player_context]["player"] = player_anim;
level._melee.info_by_type[set][type][ai_context][player_context]["ai"] = ai_anim;
level._melee.info_by_type[set][type][ai_context][player_context]["type"] = type;
if (IsDefined(ai_idle))
{
level._melee.info_by_type[set][type][ai_context][player_context]["ai_idle"] = ai_idle;
}
if (IsDefined(ai_deathpose))
{
level._melee.info_by_type[set][type][ai_context][player_context]["ai_deathpose"] = ai_deathpose;
}
}
add_scripted_melee(name, player_anim, ai_anim, ai_idle, ai_deathpose)
{
add_melee_sequence("scripted", name, "scripted", "scripted", player_anim, ai_anim, ai_idle, ai_deathpose);
}
add_melee_callback(set, type, player_context, ai_context, callback)
{
level._melee.info[set][player_context][ai_context][type]["callback"] = callback;
level._melee.info_by_type[set][type][ai_context][player_context]["callback"] = callback;
}
do_fx()
{
while (true)
{
self waittill("contextual_melee_anim", note);
switch (note)
{
case "fx_blood":
PlayFXOnTag(level._effect["neckstab_stand_blood"], self, "J_Neck");
break;
case "fx_blood_karambit":
AssertEx( IsDefined(level._effect["karambit_stand_blood"]), "No blood effect setup for the karambit contextual melee");
if( is_mature() )
{
PlayFXOnTag(level._effect["karambit_stand_blood"], self, "J_Neck");
}
level notify( "karambit_stand_blood_now" );
break;
case "fx_blood_arm_hatchet":
PlayFXOnTag( level._effect["hatchet_arm_blood"], self, "J_Wrist_LE" );
break;
case "fx_blood_neck_hatchet":
PlayFXOnTag( level._effect["neckstab_stand_blood_left"], self, "J_Neck" );
break;
case "end":
break;
}
}
}
get_weapon(type)
{
if (IsDefined(level._melee.weapon_info[type]))
{
return level._melee.weapon_info[type];
}
}
does_melee_type_need_legs(type)
{
switch (type)
{
case "shovelslam":
case "kneekick":
case "karambit":
return true;
default:
return false;
}
}
spawn_player_hands(align_ent, info)
{
if(IsDefined(self.early_contextual_player_hands))
{
self.player_hands = self.early_contextual_player_hands;
}
else
{
start_org = GetStartOrigin(align_ent.origin, align_ent.angles, info["player"] );
start_ang = GetStartAngles(align_ent.origin, align_ent.angles, info["player"] );
self.player_hands = spawn_anim_model( "player_hands_contextual_melee", start_org, start_ang );
}
if(!IsDefined(level._contextual_melee_hide))
{
self.player_hands Hide();
}
}
spawn_player_model(align_ent, info)
{
start_org = GetStartOrigin(align_ent.origin, align_ent.angles, info["player"] );
start_ang = GetStartAngles(align_ent.origin, align_ent.angles, info["player"] );
self.player_hands = spawn_anim_model( "player_model_contextual_melee", start_org, start_ang );
self.player_hands Hide();
}
animate_player_hands(victim, info)
{
self.player_hands SetAnim( info["player"], 1, 0, 0 );
self StartCameraTween(level._CONTEXTUAL_MELEE_LERP_TIME);
self PlayerLinkToAbsolute(self.player_hands, "tag_player");
wait (level._CONTEXTUAL_MELEE_LERP_TIME / 2);
victim notify("contextual_melee_start_anim");
self.player_hands AnimScripted("contextual_melee_anim", victim._contextual_melee_align_obj.origin, victim._contextual_melee_align_obj.angles, info["player"]);
if (IsDefined(info["weapon_name"]))
{
weapon = info["weapon_name"];
if (IsDefined(info["weapon_anim"]))
{
self thread animate_weapon(weapon, info["weapon_anim"]);
}
else
{
self.player_hands Attach(weapon, "tag_weapon", true);
}
}
wait (.05);
self.player_hands Show();
self.player_hands animscripts\shared::DoNoteTracks("contextual_melee_anim");
}
#using_animtree( "animated_props" );
setup_props()
{
add_melee_weapon("default", "neckstab", "stand", "stand", "weapon_parabolic_knife");
add_melee_weapon("default", "neckstab", "stand", "crouch", "weapon_parabolic_knife");
add_melee_weapon("quick", "neckstab", "stand", "stand", "weapon_parabolic_knife");
add_melee_weapon("quick", "neckstab", "stand", "crouch", "weapon_parabolic_knife");
add_melee_weapon("default", "garrote", "stand", "stand", "t5_weapon_garrot_wire", %prop_contextual_melee_garrote_garrotewire);
add_melee_weapon("default", "garrote", "stand", "sit", "t5_weapon_garrot_wire", %prop_contextual_melee_garrotesit_garrotewire);
add_melee_weapon("quick", "garrote", "stand", "stand", "t5_weapon_garrot_wire", %prop_contextual_melee_garrote_garrotewire_quick);
add_melee_weapon("quick", "garrote", "stand", "sit", "t5_weapon_garrot_wire", %prop_contextual_melee_garrotesit_garrotewire_quick);
add_melee_prop_anim("default", "garrote", "stand", "sit", %prop_contextual_melee_garrotesit_chair);
add_melee_prop_anim("quick", "garrote", "stand", "sit", %prop_contextual_melee_garrotesit_chair_quick);
}
add_melee_weapon(set, type, player_context, ai_context, weapon_name, weapon_anim)
{
level._melee.info[set][player_context][ai_context][type]["weapon_name"] = weapon_name;
level._melee.info[set][player_context][ai_context][type]["weapon_anim"] = weapon_anim;
level._melee.info_by_type[set][type][ai_context][player_context]["weapon_name"] = weapon_name;
level._melee.info_by_type[set][type][ai_context][player_context]["weapon_anim"] = weapon_anim;
}
add_melee_prop_anim(set, type, player_context, ai_context, animation)
{
level._melee.info[set][player_context][ai_context][type]["prop_anim"] = animation;
level._melee.info_by_type[set][type][ai_context][player_context]["prop_anim"] = animation;
}
animate_weapon(weapon_name, animation)
{
weapon_org = self.player_hands GetTagOrigin("tag_weapon");
weapon_ang = self.player_hands GetTagAngles("tag_weapon");
weapon = Spawn("script_model", weapon_org);
weapon SetModel(weapon_name);
weapon UseAnimTree(#animtree);
weapon LinkTo(self.player_hands, "tag_weapon");
weapon AnimScripted("contextual_melee_weapon_anim", weapon_org, weapon_ang, animation);
weapon animscripts\shared::DoNoteTracks("contextual_melee_weapon_anim");
weapon Delete();
}
animate_prop()
{
if (IsDefined(self._melee.info["prop_anim"]))
{
self._contextual_melee_align_obj UseAnimTree(#animtree);
self._contextual_melee_align_obj AnimScripted("contextual_melee_prop_anim", self._contextual_melee_align_obj.origin, self._contextual_melee_align_obj.angles, self._melee.info["prop_anim"]);
}
}
contextual_melee_show_hintstring( string_on )
{
level._contextual_melee_print_hintstring = string_on;
}
contextual_melee_allow_fire_button( string_on )
{
level._contextual_melee_allow_fire_button = string_on;
}