mirror of
https://github.com/JezuzLizard/BO2-Reimagined.git
synced 2025-06-07 13:49:33 -05:00
526 lines
12 KiB
Plaintext
526 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.angles = (0, betty.angles[1], 0);
|
|
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);
|
|
} |