1
0
mirror of https://github.com/JezuzLizard/BO2-Reimagined.git synced 2025-06-07 21:59:49 -05:00
BO2-Reimagined/scripts/zm/reimagined/_zm_weap_bouncingbetty.gsc
Jbleezy fc74d54232 Bouncing Betty: make throwable
Bouncing Betty: use anims from AT Mine
Placeable mines: optimize last shot switch time
2024-04-11 18:24:09 -07:00

525 lines
12 KiB
Plaintext

#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\zombies\_zm_utility;
#include maps\mp\zombies\_zm_equipment;
#include maps\mp\zombies\_zm_score;
#include maps\mp\zombies\_zm_audio;
#include maps\mp\zombies\_zm_weapons;
#include maps\mp\zombies\_zm_stats;
#include maps\mp\gametypes_zm\_weaponobjects;
init()
{
if (!isdefined(level.betties_max_per_player))
level.betties_max_per_player = 20;
trigs = getentarray("betty_purchase", "targetname");
for (i = 0; i < trigs.size; i++)
{
model = getent(trigs[i].target, "targetname");
if (isdefined(model))
model hide();
}
array_thread(trigs, ::buy_betties);
level thread give_betties_after_rounds();
level.betties_on_damage = ::satchel_damage;
level.pickup_betties = ::pickup_betties;
level.pickup_betties_trigger_listener = ::pickup_betties_trigger_listener;
level._effect["betty_light"] = loadfx("weapon/bouncing_betty/fx_betty_light_green");
level._effect["betty_launch"] = loadfx("weapon/bouncing_betty/fx_betty_launch_dust");
level._effect["betty_explosion"] = loadfx("weapon/bouncing_betty/fx_betty_explosion");
}
buy_betties()
{
self.zombie_cost = 1000;
self sethintstring(&"ZOMBIE_WEAPON_BOUNCINGBETTY", self.zombie_cost);
self setcursorhint("HINT_WEAPON", "bouncingbetty_zm");
self endon("kill_trigger");
if (!isdefined(self.stub))
return;
if (isdefined(self.stub) && !isdefined(self.stub.betties_triggered))
self.stub.betties_triggered = 0;
self.betties_triggered = self.stub.betties_triggered;
while (true)
{
self waittill("trigger", who);
if (who in_revive_trigger())
continue;
if (who has_powerup_weapon())
{
wait 0.1;
continue;
}
if (is_player_valid(who))
{
if (who.score >= self.zombie_cost)
{
if (!who is_player_placeable_mine("bouncingbetty_zm") || who getWeaponAmmoStock("bouncingbetty_zm") < 2)
{
play_sound_at_pos("purchase", self.origin);
who maps\mp\zombies\_zm_score::minus_to_player_score(self.zombie_cost);
if (!who is_player_placeable_mine("bouncingbetty_zm"))
{
who thread show_betty_hint("betty_purchased");
}
who thread betty_setup();
who thread maps\mp\zombies\_zm_audio::create_and_play_dialog("weapon_pickup", "grenade");
if (isdefined(self.stub))
self.betties_triggered = self.stub.betties_triggered;
if (self.betties_triggered == 0)
{
model = getent(self.target, "targetname");
if (isdefined(model))
model thread maps\mp\zombies\_zm_weapons::weapon_show(who);
else if (isdefined(self.clientfieldname))
level setclientfield(self.clientfieldname, 1);
self.betties_triggered = 1;
if (isdefined(self.stub))
self.stub.betties_triggered = 1;
}
trigs = getentarray("betty_purchase", "targetname");
for (i = 0; i < trigs.size; i++)
trigs[i] setinvisibletoplayer(who);
}
}
else
{
who play_sound_on_ent("no_purchase");
who maps\mp\zombies\_zm_audio::create_and_play_dialog("general", "no_money_weapon");
}
}
}
}
betty_unitrigger_update_prompt(player)
{
self sethintstring(&"ZOMBIE_WEAPON_BOUNCINGBETTY", self.zombie_cost);
self setcursorhint("HINT_WEAPON", "bouncingbetty_zm");
return true;
}
betty_safe_to_plant()
{
if (self.owner.betties.size >= level.betties_max_per_player)
return 0;
if (isdefined(level.betty_safe_to_plant))
return self [[level.betty_safe_to_plant]]();
return 1;
}
betty_wait_and_detonate()
{
wait 0.1;
self bouncingbettydetonate();
}
betty_watch()
{
self endon("death");
self notify("betty_watch");
self endon("betty_watch");
while (true)
{
self waittill("grenade_fire", betty, weapname);
if (weapname == "bouncingbetty_zm")
{
betty.owner = self;
betty.team = self.team;
self notify("zmb_enable_betty_prompt");
if (betty betty_safe_to_plant())
{
if (isdefined(level.betty_planted))
self thread [[level.betty_planted]](betty);
betty thread betty_detonation();
betty thread play_betty_effects();
self maps\mp\zombies\_zm_stats::increment_client_stat("betties_planted");
self maps\mp\zombies\_zm_stats::increment_player_stat("betties_planted");
}
else
betty thread betty_wait_and_detonate();
self thread betty_last_shot_switch(weapname);
}
}
}
// empty drop anim doesn't work for weapons that use `offhandSlot\Equipment\` attribute
betty_last_shot_switch(weapname)
{
self endon("disconnect");
ammo = self getammocount(weapname);
fire_time = weaponfiretime(weapname) * 0.8;
if (self hasperk("specialty_rof"))
{
fire_time *= getdvarfloat("perk_weapRateMultiplier");
}
wait fire_time;
if (!self hasweapon(weapname))
{
return;
}
if (self getcurrentweapon() != weapname)
{
return;
}
if (ammo != 0)
{
return;
}
ammo = self getammocount(weapname);
self takeweapon(weapname);
self giveweapon(weapname);
self setweaponammoclip(weapname, ammo);
}
betty_setup()
{
if (!isdefined(self.betties))
self.betties = [];
self thread betty_watch();
self giveweapon("bouncingbetty_zm");
self set_player_placeable_mine("bouncingbetty_zm");
self setactionslot(4, "weapon", "bouncingbetty_zm");
self setweaponammostock("bouncingbetty_zm", 2);
}
adjust_trigger_origin(origin)
{
origin = origin + vectorscale((0, 0, 1), 20.0);
return origin;
}
on_spawn_retrieve_trigger(watcher, player)
{
self maps\mp\gametypes_zm\_weaponobjects::onspawnretrievableweaponobject(watcher, player);
if (isdefined(self.pickuptrigger))
self.pickuptrigger sethintlowpriority(0);
}
pickup_betties()
{
player = self.owner;
if (!player hasweapon("bouncingbetty_zm"))
{
player thread betty_watch();
player giveweapon("bouncingbetty_zm");
player set_player_placeable_mine("bouncingbetty_zm");
player setactionslot(4, "weapon", "bouncingbetty_zm");
player setweaponammoclip("bouncingbetty_zm", 0);
player notify("zmb_enable_betty_prompt");
}
else
{
clip_ammo = player getweaponammoclip(self.name);
clip_max_ammo = weaponclipsize(self.name);
if (clip_ammo >= clip_max_ammo)
{
self destroy_ent();
player notify("zmb_disable_betty_prompt");
return;
}
}
self pick_up();
clip_ammo = player getweaponammoclip(self.name);
clip_max_ammo = weaponclipsize(self.name);
if (clip_ammo >= clip_max_ammo)
player notify("zmb_disable_betty_prompt");
player maps\mp\zombies\_zm_stats::increment_client_stat("betties_pickedup");
player maps\mp\zombies\_zm_stats::increment_player_stat("betties_pickedup");
}
pickup_betties_trigger_listener(trigger, player)
{
self thread pickup_betties_trigger_listener_enable(trigger, player);
self thread pickup_betties_trigger_listener_disable(trigger, player);
}
pickup_betties_trigger_listener_enable(trigger, player)
{
self endon("delete");
self endon("death");
while (true)
{
player waittill_any("zmb_enable_betty_prompt", "spawned_player");
if (!isdefined(trigger))
return;
trigger trigger_on();
trigger linkto(self);
}
}
pickup_betties_trigger_listener_disable(trigger, player)
{
self endon("delete");
self endon("death");
while (true)
{
player waittill("zmb_disable_betty_prompt");
if (!isdefined(trigger))
return;
trigger unlink();
trigger trigger_off();
}
}
betty_detonation()
{
self endon("death");
self waittill_not_moving();
wait 0.1;
detonateradius = 96;
damagearea = spawn("trigger_radius", self.origin + (0, 0, 0 - detonateradius), 4, detonateradius, detonateradius * 2);
damagearea setexcludeteamfortrigger(self.team);
damagearea enablelinkto();
damagearea linkto(self);
if (is_true(self.isonbus))
damagearea setmovingplatformenabled(1);
self.damagearea = damagearea;
self thread delete_betties_on_death(self.owner, damagearea);
self.owner.betties[self.owner.betties.size] = self;
while (true)
{
damagearea waittill("trigger", ent);
if (isdefined(self.owner) && ent == self.owner)
continue;
if (isdefined(ent.pers) && isdefined(ent.pers["team"]) && ent.pers["team"] == self.team)
continue;
if (isDefined(ent.pers) && isDefined(ent.pers["team"]) && ent.pers["team"] == getOtherTeam(self.team))
continue;
if (isdefined(ent.ignore_betty) && ent.ignore_betty)
continue;
if (ent damageconetrace(self.origin, self) > 0)
{
self playsound("wpn_claymore_alert");
wait 0.1;
self bouncingbettydetonate();
return;
}
}
}
bouncingbettydetonate()
{
self spawnminemover();
self.minemover thread bouncingbettyjumpandexplode();
self delete();
}
spawnminemover()
{
minemover = spawn("script_model", self.origin);
minemover.angles = self.angles;
minemover setmodel(self.model);
minemover.owner = self.owner;
self.minemover = minemover;
}
bouncingbettyjumpandexplode()
{
vars = [];
vars["bettyjumpheight"] = 65;
vars["bettyjumptime"] = 0.65;
vars["bettyrotatevelocity"] = (0, 750, 32);
vars["explodepos"] = self.origin + (0, 0, vars["bettyjumpheight"]);
self moveto(vars["explodepos"], vars["bettyjumptime"], vars["bettyjumptime"], 0);
playfx(level._effect["betty_launch"], self.origin);
self rotatevelocity(vars["bettyrotatevelocity"], vars["bettyjumptime"], 0, vars["bettyjumptime"]);
self playsound("fly_betty_jump");
wait(vars["bettyjumptime"]);
self thread mineexplode();
}
mineexplode()
{
vars = [];
vars["bettydamageradius"] = 256;
vars["bettydamagemax"] = 200;
vars["bettydamagemin"] = 50;
if (!isdefined(self) || !isdefined(self.owner))
return;
self playsound("fly_betty_explo");
wait 0.05;
if (!isdefined(self) || !isdefined(self.owner))
return;
self hide();
self radiusdamage(self.origin, vars["bettydamageradius"], vars["bettydamagemax"], vars["bettydamagemin"], self.owner, "MOD_EXPLOSIVE", "bouncingbetty_zm");
playfx(level._effect["betty_explosion"], self.origin);
wait 0.2;
if (!isdefined(self) || !isdefined(self.owner))
return;
if (isdefined(self.trigger))
self.trigger delete();
self delete();
}
delete_betties_on_death(player, ent)
{
self waittill("death");
if (isdefined(player))
arrayremovevalue(player.betties, self);
wait 0.05;
if (isdefined(ent))
ent delete();
}
satchel_damage()
{
self endon("death");
self setcandamage(1);
self.health = 100000;
self.maxhealth = self.health;
attacker = undefined;
while (true)
{
self waittill("damage", amount, attacker);
if (!isdefined(self))
return;
self.health = self.maxhealth;
if (!isplayer(attacker))
continue;
if (isdefined(self.owner) && attacker == self.owner)
continue;
if (isdefined(attacker.pers) && isdefined(attacker.pers["team"]) && attacker.pers["team"] != level.zombie_team)
continue;
break;
}
if (level.satchelexplodethisframe)
wait(0.1 + randomfloat(0.4));
else
wait 0.05;
if (!isdefined(self))
return;
level.satchelexplodethisframe = 1;
thread reset_satchel_explode_this_frame();
self detonate(attacker);
}
reset_satchel_explode_this_frame()
{
wait 0.05;
level.satchelexplodethisframe = 0;
}
play_betty_effects()
{
self endon("death");
self waittill_not_moving();
playfxontag(level._effect["betty_light"], self, "tag_origin");
}
give_betties_after_rounds()
{
while (true)
{
level waittill("between_round_over");
if (!level flag_exists("teleporter_used") || !flag("teleporter_used"))
{
players = get_players();
for (i = 0; i < players.size; i++)
{
if (players[i] is_player_placeable_mine("bouncingbetty_zm"))
{
players[i] giveweapon("bouncingbetty_zm");
players[i] set_player_placeable_mine("bouncingbetty_zm");
players[i] setactionslot(4, "weapon", "bouncingbetty_zm");
players[i] setweaponammoclip("bouncingbetty_zm", 2);
}
}
}
}
}
show_betty_hint(string)
{
self endon("death");
self endon("disconnect");
if (string == "betty_purchased")
text = &"ZOMBIE_BETTY_HOWTO";
else
text = &"ZOMBIE_BETTY_ALREADY_PURCHASED";
show_equipment_hint_text(text);
}