MULTITEAM_INFO##teams(default,prefix,strnum,flnum,args,hudargs,icon,normal,gentle)
#define MSG_INFO_NOTIFICATIONS \
+ MSG_INFO_NOTIF(2, INFO_CHAT_NOSPECTATORS, 0, 0, "", "", "", _("^F4NOTE: ^BGSpectator chat is not sent to players during the match"), "") \
+ MSG_INFO_NOTIF(2, INFO_COINTOSS, 1, 0, "s1", "", "", _("^F2Throwing coin... Result: %s^F2!"), "") \
+ MSG_INFO_NOTIF(1, INFO_JETPACK_NOFUEL, 0, 0, "", "", "", _("^BGYou don't have any fuel for the ^F1Jetpack"), "") \
+ MSG_INFO_NOTIF(2, INFO_SUPERSPEC_MISSING_UID, 0, 0, "", "", "", _("^F2You lack a UID, superspec options will not be saved/restored"), "") \
++ MSG_INFO_NOTIF(1, INFO_CA_JOIN_LATE, 0, 0, "", "", "", _("^F1Round already started, you will join the game in the next round"), "") \
++ MSG_INFO_NOTIF(1, INFO_CA_LEAVE, 0, 0, "", "", "", _("^F2You will spectate in the next round"), "") \
MULTITEAM_INFO(1, INFO_CTF_CAPTURE_, 2, 1, 0, "s1", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag"), "") \
MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 2, 2, 2, "s1 f1p2dec s2 f2p2dec", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds"), "") \
MULTITEAM_INFO(1, INFO_CTF_CAPTURE_TIME_, 2, 1, 1, "s1 f1p2dec", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_WAKI_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VOID, 2, 1, "s1 s2loc spree_lost", "s1", "notify_void", _("^BG%s^K1 was in the wrong place%s%s"), "") \
MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s"), "") \
- MSG_INFO_NOTIF(1, INFO_CA_JOIN_LATE, 0, 0, "", "", "", _("^F1Round already started, you will join the game in the next round"), "") \
- MSG_INFO_NOTIF(1, INFO_CA_LEAVE, 0, 0, "", "", "", _("^F2You will spectate in the next round"), "") \
+ MSG_INFO_NOTIF(1, INFO_DOMINATION_CAPTURE_TIME, 2, 2, "s1 s2 f1 f2", "", "", _("^BG%s^BG%s^BG (%s points every %s seconds)"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_FREEZE, 2, 0, "s1 s2", "", "", _("^BG%s^K1 was frozen by ^BG%s"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED, 2, 0, "s1 s2", "", "", _("^BG%s^K3 was revived by ^BG%s"), "") \
MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED_FALL, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by falling"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_HOOK_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponhook", _("^BG%s%s^K1 was caught in ^BG%s^K1's Hook gravity bomb%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_KLEINBOTTLE_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapontuba", _("^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_KLEINBOTTLE_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle%s%s"), "") \
- MSG_INFO_NOTIF(1, INFO_WEAPON_LASER_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponlaser", _("^BG%s%s^K1 was shot to death by ^BG%s^K1's Laser%s%s"), "") \
- MSG_INFO_NOTIF(1, INFO_WEAPON_LASER_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponlaser", _("^BG%s^K1 shot themself to hell with their Laser%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_WEAPON_MACHINEGUN_MURDER_SNIPE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponuzi", _("^BG%s%s^K1 was sniped by ^BG%s^K1's Machine Gun%s%s"), "") \
+ MSG_INFO_NOTIF(1, INFO_WEAPON_MACHINEGUN_MURDER_SPRAY, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponuzi", _("^BG%s%s^K1 was riddled full of holes by ^BG%s^K1's Machine Gun%s%s"), "") \
++ MSG_INFO_NOTIF(1, INFO_WEAPON_MINELAYER_LIMIT, 0, 1, "f1", "", "", _("^BGYou cannot place more than ^F2%s^BG mines at a time"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_MINELAYER_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponminelayer", _("^BG%s%s^K1 got too close to ^BG%s^K1's mine%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_MINELAYER_SUICIDE, 2, 1, "s1 s2loc spree_lost", "s1", "weaponminelayer", _("^BG%s^K1 forgot about their mine%s%s"), "") \
- MSG_INFO_NOTIF(1, INFO_WEAPON_MINSTANEX_MURDER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weaponminstanex", _("^BG%s%s^K1 has been vaporized by ^BG%s^K1's Minstanex%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_MURDER_BOUNCE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapongrenadelauncher", _("^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_MURDER_EXPLODE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "weapongrenadelauncher", _("^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"), "") \
MSG_INFO_NOTIF(1, INFO_WEAPON_MORTAR_SUICIDE_BOUNCE, 2, 1, "s1 s2loc spree_lost", "s1", "weapongrenadelauncher", _("^BG%s^K1 didn't see their own Mortar grenade%s%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_ROUNDSTART, 0, 1, "", CPID_KEYHUNT_OTHER, "1 f1", _("^F4Round will start in ^COUNT"), "") \
MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_SCAN, 0, 1, "", CPID_KEYHUNT_OTHER, "f1 0", _("^BGScanning frequency range..."), "") \
MULTITEAM_CENTER(1, CENTER_KEYHUNT_START_, 4, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGYou are starting with the ^TC^TT Key"), "") \
- MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT, 0, 4, "missing_teams", CPID_KEYHUNT_OTHER, "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
- MSG_CENTER_NOTIF(1, CENTER_MISSING_TEAMS, 0, 4, "missing_teams", CPID_MISSING_TEAMS, "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT, 0, 1, "missing_teams", CPID_KEYHUNT_OTHER, "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
++ MSG_CENTER_NOTIF(1, CENTER_LMS_NOLIVES, 0, 0, "", CPID_LMS, "0 0", _("^BGYou have no lives left, you must wait until the next match"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_MISSING_TEAMS, 0, 1, "missing_teams", CPID_MISSING_TEAMS, "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
MSG_CENTER_NOTIF(1, CENTER_MISSING_PLAYERS, 0, 1, "f1", CPID_MISSING_PLAYERS, "-1 0", _("^BGWaiting for %s player(s) to join..."), "") \
- MSG_CENTER_NOTIF(1, CENTER_MINSTA_FINDAMMO, 0, 0, "", CPID_MINSTA_FINDAMMO, "1 9", _("^F4^COUNT^BG left to find some ammo!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_MINSTA_FINDAMMO_FIRST, 0, 0, "", CPID_MINSTA_FINDAMMO, "1 10", _("^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"), _("^BGGet some ammo! ^F4^COUNT^BG left!")) \
- MSG_CENTER_NOTIF(1, CENTER_MINSTA_LIVES_REMAINING, 0, 1, "f1", NO_CPID, "0 0", _("^F2Extra lives remaining: ^K1%s"), "") \
- MSG_CENTER_NOTIF(1, CENTER_MINSTA_SECONDARY, 0, 0, "", NO_CPID, "0 0", _("^BGSecondary fire inflicts no damage!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_MOTD, 1, 0, "s1", CPID_MOTD, "-1 0", _("^BG%s"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_INSTAGIB_FINDAMMO, 0, 0, "", CPID_INSTAGIB_FINDAMMO,"1 9", _("^F4^COUNT^BG left to find some ammo!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_INSTAGIB_FINDAMMO_FIRST, 0, 0, "", CPID_INSTAGIB_FINDAMMO,"1 10", _("^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"), _("^BGGet some ammo! ^F4^COUNT^BG left!")) \
+ MSG_CENTER_NOTIF(1, CENTER_INSTAGIB_LIVES_REMAINING, 0, 1, "f1", NO_CPID, "0 0", _("^F2Extra lives remaining: ^K1%s"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_MOTD, 1, 0, "s1", CPID_MOTD, "-1 0", "^BG%s", "") \
MSG_CENTER_NOTIF(1, CENTER_NIX_COUNTDOWN, 0, 2, "item_wepname", CPID_NIX, "1 f2", _("^F2^COUNT^BG until weapon change...\nNext weapon: ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_NIX_NEWWEAPON, 0, 1, "item_wepname", CPID_NIX, "0 0", _("^F2Active weapon: ^F1%s"), "") \
MSG_CENTER_NOTIF(1, CENTER_NADE, 0, 0, "", NO_CPID, "0 0", _("^BGPress ^F2DROPWEAPON^BG again to toss the grenade!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_ONS_NOTSHIELDED, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^K1Your generator is NOT shielded!\n^BGRe-capture controlpoints to shield it!"), "") \
MSG_CENTER_NOTIF(1, CENTER_OVERTIME_FRAG, 0, 0, "", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\nKeep fragging until we have a winner!"), _("^F2Now playing ^F4OVERTIME^F2!\nKeep scoring until we have a winner!")) \
- MSG_CENTER_NOTIF(1, CENTER_OVERTIME_CONTROLPOINT, 0, 0, "", CPID_OVERTIME, "3 0", _("^F2Now playing ^F4OVERTIME^F2!\n\nGenerators start now to decay.\nThe more control points your team holds,\nthe faster the enemy generator decays"), "") \
++ MSG_CENTER_NOTIF(1, CENTER_OVERTIME_CONTROLPOINT, 0, 0, "", CPID_OVERTIME, "5 0", _("^F2Now playing ^F4OVERTIME^F2!\n\nGenerators are now decaying.\nThe more control points your team holds,\nthe faster the enemy generator decays"), "") \
MSG_CENTER_NOTIF(1, CENTER_OVERTIME_TIME, 0, 1, "f1time", CPID_OVERTIME, "0 0", _("^F2Now playing ^F4OVERTIME^F2!\n^BGAdded ^F4%s^BG to the game!"), "") \
- MSG_CENTER_NOTIF(1, CENTER_PORTO_FAILED, 0, 0, "", NO_CPID, "0 0", _("^K1Portal deployment failed.\n\n^F2Catch it to try again!"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_PORTO_CREATED_IN, 0, 0, "", NO_CPID, "0 0", _("^K1In^BG-portal created"), "") \
+ MSG_CENTER_NOTIF(1, CENTER_PORTO_CREATED_OUT, 0, 0, "", NO_CPID, "0 0", _("^F3Out^BG-portal created"), "") \
++ MSG_CENTER_NOTIF(1, CENTER_PORTO_FAILED, 0, 0, "", NO_CPID, "0 0", _("^K1Portal deployment failed.\n\n^F2Catch it to try again!"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERDOWN_INVISIBILITY, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Invisibility has worn off"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERDOWN_SHIELD, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Shield has worn off"), "") \
MSG_CENTER_NOTIF(1, CENTER_POWERDOWN_SPEED, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Speed has worn off"), "") \
MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SPECTATE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Spectating in ^COUNT"), "") \
MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SUICIDE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Suicide in ^COUNT"), "") \
MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_BEGINNING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout begins in ^COUNT"), "") \
- MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "")
- MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "")
++ MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "") \
++ MSG_CENTER_NOTIF(1, CENTER_WEAPON_MINELAYER_LIMIT, 0, 1, "f1", NO_CPID, "0 0", _("^BGYou cannot place more than ^F2%s^BG mines at a time"), "")
#define MULTITEAM_MULTI2(default,prefix,anncepre,infopre,centerpre) \
MSG_MULTI_NOTIF(default, prefix##RED, anncepre##RED, infopre##RED, centerpre##RED) \
MSG_MULTI_NOTIF(1, ITEM_WEAPON_NOAMMO, NO_MSG, INFO_ITEM_WEAPON_NOAMMO, CENTER_ITEM_WEAPON_NOAMMO) \
MSG_MULTI_NOTIF(1, ITEM_WEAPON_PRIMORSEC, NO_MSG, INFO_ITEM_WEAPON_PRIMORSEC, CENTER_ITEM_WEAPON_PRIMORSEC) \
MSG_MULTI_NOTIF(1, ITEM_WEAPON_UNAVAILABLE, NO_MSG, INFO_ITEM_WEAPON_UNAVAILABLE, CENTER_ITEM_WEAPON_UNAVAILABLE) \
+ MSG_MULTI_NOTIF(1, MULTI_COINTOSS, NO_MSG, INFO_COINTOSS, CENTER_COINTOSS) \
MSG_MULTI_NOTIF(1, MULTI_COUNTDOWN_BEGIN, ANNCE_BEGIN, NO_MSG, CENTER_COUNTDOWN_BEGIN) \
- MSG_MULTI_NOTIF(1, MULTI_MINSTA_FINDAMMO, ANNCE_NUM_10, NO_MSG, CENTER_MINSTA_FINDAMMO_FIRST) \
+ MSG_MULTI_NOTIF(1, MULTI_INSTAGIB_FINDAMMO, ANNCE_NUM_10, NO_MSG, CENTER_INSTAGIB_FINDAMMO_FIRST) \
MSG_MULTI_NOTIF(1, WEAPON_ACCORDEON_MURDER, NO_MSG, INFO_WEAPON_ACCORDEON_MURDER, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_ACCORDEON_SUICIDE, NO_MSG, INFO_WEAPON_ACCORDEON_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_ARC_MURDER, NO_MSG, INFO_WEAPON_ARC_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_BLASTER_MURDER, NO_MSG, INFO_WEAPON_BLASTER_MURDER, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_BLASTER_SUICIDE, NO_MSG, INFO_WEAPON_BLASTER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
MSG_MULTI_NOTIF(1, WEAPON_CRYLINK_MURDER, NO_MSG, INFO_WEAPON_CRYLINK_MURDER, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_CRYLINK_SUICIDE, NO_MSG, INFO_WEAPON_CRYLINK_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_DEVASTATOR_MURDER_DIRECT, NO_MSG, INFO_WEAPON_DEVASTATOR_MURDER_DIRECT, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_DEVASTATOR_MURDER_SPLASH, NO_MSG, INFO_WEAPON_DEVASTATOR_MURDER_SPLASH, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_DEVASTATOR_SUICIDE, NO_MSG, INFO_WEAPON_DEVASTATOR_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_BOLT, NO_MSG, INFO_WEAPON_ELECTRO_MURDER_BOLT, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_COMBO, NO_MSG, INFO_WEAPON_ELECTRO_MURDER_COMBO, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_ELECTRO_MURDER_ORBS, NO_MSG, INFO_WEAPON_ELECTRO_MURDER_ORBS, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_HOOK_MURDER, NO_MSG, INFO_WEAPON_HOOK_MURDER, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_KLEINBOTTLE_MURDER, NO_MSG, INFO_WEAPON_KLEINBOTTLE_MURDER, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_KLEINBOTTLE_SUICIDE, NO_MSG, INFO_WEAPON_KLEINBOTTLE_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_LASER_MURDER, NO_MSG, INFO_WEAPON_LASER_MURDER, NO_MSG) \
- MSG_MULTI_NOTIF(1, WEAPON_LASER_SUICIDE, NO_MSG, INFO_WEAPON_LASER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
+ MSG_MULTI_NOTIF(1, WEAPON_MACHINEGUN_MURDER_SNIPE, NO_MSG, INFO_WEAPON_MACHINEGUN_MURDER_SNIPE, NO_MSG) \
+ MSG_MULTI_NOTIF(1, WEAPON_MACHINEGUN_MURDER_SPRAY, NO_MSG, INFO_WEAPON_MACHINEGUN_MURDER_SPRAY, NO_MSG) \
++ MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_LIMIT, NO_MSG, INFO_WEAPON_MINELAYER_LIMIT, CENTER_WEAPON_MINELAYER_LIMIT) \
MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_MURDER, NO_MSG, INFO_WEAPON_MINELAYER_MURDER, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_MINELAYER_SUICIDE, NO_MSG, INFO_WEAPON_MINELAYER_SUICIDE, CENTER_DEATH_SELF_GENERIC) \
- MSG_MULTI_NOTIF(1, WEAPON_MINSTANEX_MURDER, NO_MSG, INFO_WEAPON_MINSTANEX_MURDER, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_MORTAR_MURDER_BOUNCE, NO_MSG, INFO_WEAPON_MORTAR_MURDER_BOUNCE, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_MORTAR_MURDER_EXPLODE, NO_MSG, INFO_WEAPON_MORTAR_MURDER_EXPLODE, NO_MSG) \
MSG_MULTI_NOTIF(1, WEAPON_MORTAR_SUICIDE_BOUNCE, NO_MSG, INFO_WEAPON_MORTAR_SUICIDE_BOUNCE, CENTER_DEATH_SELF_GENERIC) \
--- /dev/null
- sprint(self, strcat("minelayer: You cannot place more than ^2", ftos(WEP_CVAR(minelayer, limit)), " ^7mines at a time\n") );
+ #ifdef REGISTER_WEAPON
+ REGISTER_WEAPON(
+ /* WEP_##id */ MINE_LAYER,
+ /* function */ W_MineLayer,
+ /* ammotype */ ammo_rockets,
+ /* impulse */ 4,
+ /* flags */ WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH,
+ /* rating */ BOT_PICKUP_RATING_HIGH,
+ /* color */ '0.75 1 0',
+ /* modelname */ "minelayer",
+ /* simplemdl */ "foobar",
+ /* crosshair */ "gfx/crosshairminelayer 0.9",
+ /* wepimg */ "weaponminelayer",
+ /* refname */ "minelayer",
+ /* wepname */ _("Mine Layer")
+ );
+
+ #define MINELAYER_SETTINGS(w_cvar,w_prop) MINELAYER_SETTINGS_LIST(w_cvar, w_prop, MINE_LAYER, minelayer)
+ #define MINELAYER_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+ w_cvar(id, sn, NONE, ammo) \
+ w_cvar(id, sn, NONE, animtime) \
+ w_cvar(id, sn, NONE, damage) \
+ w_cvar(id, sn, NONE, damageforcescale) \
+ w_cvar(id, sn, NONE, detonatedelay) \
+ w_cvar(id, sn, NONE, edgedamage) \
+ w_cvar(id, sn, NONE, force) \
+ w_cvar(id, sn, NONE, health) \
+ w_cvar(id, sn, NONE, lifetime) \
+ w_cvar(id, sn, NONE, lifetime_countdown) \
+ w_cvar(id, sn, NONE, limit) \
+ w_cvar(id, sn, NONE, protection) \
+ w_cvar(id, sn, NONE, proximityradius) \
+ w_cvar(id, sn, NONE, radius) \
+ w_cvar(id, sn, NONE, refire) \
+ w_cvar(id, sn, NONE, remote_damage) \
+ w_cvar(id, sn, NONE, remote_edgedamage) \
+ w_cvar(id, sn, NONE, remote_force) \
+ w_cvar(id, sn, NONE, remote_radius) \
+ w_cvar(id, sn, NONE, speed) \
+ w_cvar(id, sn, NONE, time) \
+ w_prop(id, sn, float, reloading_ammo, reload_ammo) \
+ w_prop(id, sn, float, reloading_time, reload_time) \
+ w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \
+ w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \
+ w_prop(id, sn, string, weaponreplace, weaponreplace) \
+ w_prop(id, sn, float, weaponstart, weaponstart) \
+ w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \
+ w_prop(id, sn, float, weaponthrowable, weaponthrowable)
+
+ #ifdef SVQC
+ MINELAYER_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+ void W_MineLayer_Think(void);
+ .float minelayer_detonate, mine_explodeanyway;
+ .float mine_time;
+ .vector mine_orientation;
+ #endif
+ #else
+ #ifdef SVQC
+ void spawnfunc_weapon_minelayer(void) { weapon_defaultspawnfunc(WEP_MINE_LAYER); }
+
+ void W_MineLayer_Stick(entity to)
+ {
+ spamsound(self, CH_SHOTS, "weapons/mine_stick.wav", VOL_BASE, ATTN_NORM);
+
+ // in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile
+
+ entity newmine;
+ newmine = spawn();
+ newmine.classname = self.classname;
+
+ newmine.bot_dodge = self.bot_dodge;
+ newmine.bot_dodgerating = self.bot_dodgerating;
+
+ newmine.owner = self.owner;
+ newmine.realowner = self.realowner;
+ setsize(newmine, '-4 -4 -4', '4 4 4');
+ setorigin(newmine, self.origin);
+ setmodel(newmine, "models/mine.md3");
+ newmine.angles = vectoangles(-trace_plane_normal); // face against the surface
+
+ newmine.mine_orientation = -trace_plane_normal;
+
+ newmine.takedamage = self.takedamage;
+ newmine.damageforcescale = self.damageforcescale;
+ newmine.health = self.health;
+ newmine.event_damage = self.event_damage;
+ newmine.spawnshieldtime = self.spawnshieldtime;
+ newmine.damagedbycontents = TRUE;
+
+ newmine.movetype = MOVETYPE_NONE; // lock the mine in place
+ newmine.projectiledeathtype = self.projectiledeathtype;
+
+ newmine.mine_time = self.mine_time;
+
+ newmine.touch = func_null;
+ newmine.think = W_MineLayer_Think;
+ newmine.nextthink = time;
+ newmine.cnt = self.cnt;
+ newmine.flags = self.flags;
+
+ remove(self);
+ self = newmine;
+
+ if(to)
+ SetMovetypeFollow(self, to);
+ }
+
+ void W_MineLayer_Explode(void)
+ {
+ if(other.takedamage == DAMAGE_AIM)
+ if(IS_PLAYER(other))
+ if(DIFF_TEAM(self.realowner, other))
+ if(other.deadflag == DEAD_NO)
+ if(IsFlying(other))
+ Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+
+ self.event_damage = func_null;
+ self.takedamage = DAMAGE_NO;
+
+ RadiusDamage(self, self.realowner, WEP_CVAR(minelayer, damage), WEP_CVAR(minelayer, edgedamage), WEP_CVAR(minelayer, radius), world, world, WEP_CVAR(minelayer, force), self.projectiledeathtype, other);
+
+ if(self.realowner.weapon == WEP_MINE_LAYER)
+ {
+ entity oldself;
+ oldself = self;
+ self = self.realowner;
+ if(!WEP_ACTION(WEP_MINE_LAYER, WR_CHECKAMMO1))
+ {
+ self.cnt = WEP_MINE_LAYER;
+ ATTACK_FINISHED(self) = time;
+ self.switchweapon = w_getbestweapon(self);
+ }
+ self = oldself;
+ }
+ self.realowner.minelayer_mines -= 1;
+ remove(self);
+ }
+
+ void W_MineLayer_DoRemoteExplode(void)
+ {
+ self.event_damage = func_null;
+ self.takedamage = DAMAGE_NO;
+
+ if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
+ self.velocity = self.mine_orientation; // particle fx and decals need .velocity
+
+ RadiusDamage(self, self.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius), world, world, WEP_CVAR(minelayer, remote_force), self.projectiledeathtype | HITTYPE_BOUNCE, world);
+
+ if(self.realowner.weapon == WEP_MINE_LAYER)
+ {
+ entity oldself;
+ oldself = self;
+ self = self.realowner;
+ if(!WEP_ACTION(WEP_MINE_LAYER, WR_CHECKAMMO1))
+ {
+ self.cnt = WEP_MINE_LAYER;
+ ATTACK_FINISHED(self) = time;
+ self.switchweapon = w_getbestweapon(self);
+ }
+ self = oldself;
+ }
+ self.realowner.minelayer_mines -= 1;
+ remove(self);
+ }
+
+ void W_MineLayer_RemoteExplode(void)
+ {
+ if(self.realowner.deadflag == DEAD_NO)
+ if((self.spawnshieldtime >= 0)
+ ? (time >= self.spawnshieldtime) // timer
+ : (vlen(NearestPointOnBox(self.realowner, self.origin) - self.origin) > WEP_CVAR(minelayer, remote_radius)) // safety device
+ )
+ {
+ W_MineLayer_DoRemoteExplode();
+ }
+ }
+
+ void W_MineLayer_ProximityExplode(void)
+ {
+ // make sure no friend is in the mine's radius. If there is any, explosion is delayed until he's at a safe distance
+ if(WEP_CVAR(minelayer, protection) && self.mine_explodeanyway == 0)
+ {
+ entity head;
+ head = findradius(self.origin, WEP_CVAR(minelayer, radius));
+ while(head)
+ {
+ if(head == self.realowner || SAME_TEAM(head, self.realowner))
+ return;
+ head = head.chain;
+ }
+ }
+
+ self.mine_time = 0;
+ W_MineLayer_Explode();
+ }
+
+ float W_MineLayer_Count(entity e)
+ {
+ float minecount = 0;
+ entity mine;
+ for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.realowner == e)
+ minecount += 1;
+
+ return minecount;
+ }
+
+ void W_MineLayer_Think(void)
+ {
+ entity head;
+
+ self.nextthink = time;
+
+ if(self.movetype == MOVETYPE_FOLLOW)
+ {
+ if(LostMovetypeFollow(self))
+ {
+ UnsetMovetypeFollow(self);
+ self.movetype = MOVETYPE_NONE;
+ }
+ }
+
+ // our lifetime has expired, it's time to die - mine_time just allows us to play a sound for this
+ // TODO: replace this mine_trigger.wav sound with a real countdown
+ if((time > self.cnt) && (!self.mine_time) && (self.cnt > 0))
+ {
+ if(WEP_CVAR(minelayer, lifetime_countdown) > 0)
+ spamsound(self, CH_SHOTS, "weapons/mine_trigger.wav", VOL_BASE, ATTN_NORM);
+ self.mine_time = time + WEP_CVAR(minelayer, lifetime_countdown);
+ self.mine_explodeanyway = 1; // make the mine super aggressive -- Samual: Rather, make it not care if a team mate is near.
+ }
+
+ // a player's mines shall explode if he disconnects or dies
+ // TODO: Do this on team change too -- Samual: But isn't a player killed when they switch teams?
+ if(!IS_PLAYER(self.realowner) || self.realowner.deadflag != DEAD_NO || self.realowner.frozen)
+ {
+ other = world;
+ self.projectiledeathtype |= HITTYPE_BOUNCE;
+ W_MineLayer_Explode();
+ return;
+ }
+
+ // set the mine for detonation when a foe gets close enough
+ head = findradius(self.origin, WEP_CVAR(minelayer, proximityradius));
+ while(head)
+ {
+ if(IS_PLAYER(head) && head.deadflag == DEAD_NO && !head.frozen)
+ if(head != self.realowner && DIFF_TEAM(head, self.realowner)) // don't trigger for team mates
+ if(!self.mine_time)
+ {
+ spamsound(self, CH_SHOTS, "weapons/mine_trigger.wav", VOL_BASE, ATTN_NORM);
+ self.mine_time = time + WEP_CVAR(minelayer, time);
+ }
+ head = head.chain;
+ }
+
+ // explode if it's time to
+ if(self.mine_time && time >= self.mine_time)
+ {
+ W_MineLayer_ProximityExplode();
+ return;
+ }
+
+ // remote detonation
+ if(self.realowner.weapon == WEP_MINE_LAYER)
+ if(self.realowner.deadflag == DEAD_NO)
+ if(self.minelayer_detonate)
+ W_MineLayer_RemoteExplode();
+ }
+
+ void W_MineLayer_Touch(void)
+ {
+ if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
+ return; // we're already a stuck mine, why do we get called? TODO does this even happen?
+
+ if(WarpZone_Projectile_Touch())
+ {
+ if(wasfreed(self))
+ self.realowner.minelayer_mines -= 1;
+ return;
+ }
+
+ if(other && IS_PLAYER(other) && other.deadflag == DEAD_NO)
+ {
+ // hit a player
+ // don't stick
+ }
+ else
+ {
+ W_MineLayer_Stick(other);
+ }
+ }
+
+ void W_MineLayer_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+ {
+ if(self.health <= 0)
+ return;
+
+ float is_from_enemy = (inflictor.realowner != self.realowner);
+
+ if(!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, (is_from_enemy ? 1 : -1)))
+ return; // g_projectiles_damage says to halt
+
+ self.health = self.health - damage;
+ self.angles = vectoangles(self.velocity);
+
+ if(self.health <= 0)
+ W_PrepareExplosionByDamage(attacker, W_MineLayer_Explode);
+ }
+
+ void W_MineLayer_Attack(void)
+ {
+ entity mine;
+ entity flash;
+
+ // scan how many mines we placed, and return if we reached our limit
+ if(WEP_CVAR(minelayer, limit))
+ {
+ if(self.minelayer_mines >= WEP_CVAR(minelayer, limit))
+ {
+ // the refire delay keeps this message from being spammed
++ Send_Notification(NOTIF_ONE, self, MSG_MULTI, WEAPON_MINELAYER_LIMIT, WEP_CVAR(minelayer, limit));
+ play2(self, "weapons/unavailable.wav");
+ return;
+ }
+ }
+
+ W_DecreaseAmmo(WEP_CVAR(minelayer, ammo));
+
+ W_SetupShot_ProjectileSize(self, '-4 -4 -4', '4 4 4', FALSE, 5, "weapons/mine_fire.wav", CH_WEAPON_A, WEP_CVAR(minelayer, damage));
+ pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
+
+ mine = WarpZone_RefSys_SpawnSameRefSys(self);
+ mine.owner = mine.realowner = self;
+ if(WEP_CVAR(minelayer, detonatedelay) >= 0)
+ mine.spawnshieldtime = time + WEP_CVAR(minelayer, detonatedelay);
+ else
+ mine.spawnshieldtime = -1;
+ mine.classname = "mine";
+ mine.bot_dodge = TRUE;
+ mine.bot_dodgerating = WEP_CVAR(minelayer, damage) * 2; // * 2 because it can detonate inflight which makes it even more dangerous
+
+ mine.takedamage = DAMAGE_YES;
+ mine.damageforcescale = WEP_CVAR(minelayer, damageforcescale);
+ mine.health = WEP_CVAR(minelayer, health);
+ mine.event_damage = W_MineLayer_Damage;
+ mine.damagedbycontents = TRUE;
+
+ mine.movetype = MOVETYPE_TOSS;
+ PROJECTILE_MAKETRIGGER(mine);
+ mine.projectiledeathtype = WEP_MINE_LAYER;
+ setsize(mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
+
+ setorigin(mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point
+ W_SetupProjVelocity_Basic(mine, WEP_CVAR(minelayer, speed), 0);
+ mine.angles = vectoangles(mine.velocity);
+
+ mine.touch = W_MineLayer_Touch;
+ mine.think = W_MineLayer_Think;
+ mine.nextthink = time;
+ mine.cnt = (WEP_CVAR(minelayer, lifetime) - WEP_CVAR(minelayer, lifetime_countdown));
+ mine.flags = FL_PROJECTILE;
+ mine.missile_flags = MIF_SPLASH | MIF_ARC | MIF_PROXY;
+
+ if(mine.cnt > 0) { mine.cnt += time; }
+
+ CSQCProjectile(mine, TRUE, PROJECTILE_MINE, TRUE);
+
+ // muzzle flash for 1st person view
+ flash = spawn();
+ setmodel(flash, "models/flash.md3"); // precision set below
+ SUB_SetFade(flash, time, 0.1);
+ flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+ W_AttachToShotorg(flash, '5 0 0');
+
+ // common properties
+
+ other = mine; MUTATOR_CALLHOOK(EditProjectile);
+
+ self.minelayer_mines = W_MineLayer_Count(self);
+ }
+
+ float W_MineLayer_PlacedMines(float detonate)
+ {
+ entity mine;
+ float minfound = 0;
+
+ for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.realowner == self)
+ {
+ if(detonate)
+ {
+ if(!mine.minelayer_detonate)
+ {
+ mine.minelayer_detonate = TRUE;
+ minfound = 1;
+ }
+ }
+ else
+ minfound = 1;
+ }
+ return minfound;
+ }
+
+ float W_MineLayer(float req)
+ {
+ entity mine;
+ float ammo_amount;
+ switch(req)
+ {
+ case WR_AIM:
+ {
+ // aim and decide to fire if appropriate
+ if(self.minelayer_mines >= WEP_CVAR(minelayer, limit))
+ self.BUTTON_ATCK = FALSE;
+ else
+ self.BUTTON_ATCK = bot_aim(WEP_CVAR(minelayer, speed), 0, WEP_CVAR(minelayer, lifetime), FALSE);
+ if(skill >= 2) // skill 0 and 1 bots won't detonate mines!
+ {
+ // decide whether to detonate mines
+ entity targetlist, targ;
+ float edgedamage, coredamage, edgeradius, recipricoledgeradius, d;
+ float selfdamage, teamdamage, enemydamage;
+ edgedamage = WEP_CVAR(minelayer, edgedamage);
+ coredamage = WEP_CVAR(minelayer, damage);
+ edgeradius = WEP_CVAR(minelayer, radius);
+ recipricoledgeradius = 1 / edgeradius;
+ selfdamage = 0;
+ teamdamage = 0;
+ enemydamage = 0;
+ targetlist = findchainfloat(bot_attack, TRUE);
+ mine = find(world, classname, "mine");
+ while(mine)
+ {
+ if(mine.realowner != self)
+ {
+ mine = find(mine, classname, "mine");
+ continue;
+ }
+ targ = targetlist;
+ while(targ)
+ {
+ d = vlen(targ.origin + (targ.mins + targ.maxs) * 0.5 - mine.origin);
+ d = bound(0, edgedamage + (coredamage - edgedamage) * sqrt(1 - d * recipricoledgeradius), 10000);
+ // count potential damage according to type of target
+ if(targ == self)
+ selfdamage = selfdamage + d;
+ else if(targ.team == self.team && teamplay)
+ teamdamage = teamdamage + d;
+ else if(bot_shouldattack(targ))
+ enemydamage = enemydamage + d;
+ targ = targ.chain;
+ }
+ mine = find(mine, classname, "mine");
+ }
+ float desirabledamage;
+ desirabledamage = enemydamage;
+ if(time > self.invincible_finished && time > self.spawnshieldtime)
+ desirabledamage = desirabledamage - selfdamage * autocvar_g_balance_selfdamagepercent;
+ if(teamplay && self.team)
+ desirabledamage = desirabledamage - teamdamage;
+
+ mine = find(world, classname, "mine");
+ while(mine)
+ {
+ if(mine.realowner != self)
+ {
+ mine = find(mine, classname, "mine");
+ continue;
+ }
+ makevectors(mine.v_angle);
+ targ = targetlist;
+ if(skill > 9) // normal players only do this for the target they are tracking
+ {
+ targ = targetlist;
+ while(targ)
+ {
+ if(
+ (v_forward * normalize(mine.origin - targ.origin)< 0.1)
+ && desirabledamage > 0.1*coredamage
+ )self.BUTTON_ATCK2 = TRUE;
+ targ = targ.chain;
+ }
+ }else{
+ float distance; distance= bound(300,vlen(self.origin-self.enemy.origin),30000);
+ //As the distance gets larger, a correct detonation gets near imposible
+ //Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
+ if(v_forward * normalize(mine.origin - self.enemy.origin)< 0.1)
+ if(IS_PLAYER(self.enemy))
+ if(desirabledamage >= 0.1*coredamage)
+ if(random()/distance*300 > frametime*bound(0,(10-skill)*0.2,1))
+ self.BUTTON_ATCK2 = TRUE;
+ // dprint(ftos(random()/distance*300),">");dprint(ftos(frametime*bound(0,(10-skill)*0.2,1)),"\n");
+ }
+
+ mine = find(mine, classname, "mine");
+ }
+ // if we would be doing at X percent of the core damage, detonate it
+ // but don't fire a new shot at the same time!
+ if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
+ self.BUTTON_ATCK2 = TRUE;
+ if((skill > 6.5) && (selfdamage > self.health))
+ self.BUTTON_ATCK2 = FALSE;
+ //if(self.BUTTON_ATCK2 == TRUE)
+ // dprint(ftos(desirabledamage),"\n");
+ if(self.BUTTON_ATCK2 == TRUE) self.BUTTON_ATCK = FALSE;
+ }
+
+ return TRUE;
+ }
+ case WR_THINK:
+ {
+ if(autocvar_g_balance_minelayer_reload_ammo && self.clip_load < WEP_CVAR(minelayer, ammo)) // forced reload
+ {
+ // not if we're holding the minelayer without enough ammo, but can detonate existing mines
+ if(!(W_MineLayer_PlacedMines(FALSE) && self.WEP_AMMO(MINE_LAYER) < WEP_CVAR(minelayer, ammo)))
+ WEP_ACTION(self.weapon, WR_RELOAD);
+ }
+ else if(self.BUTTON_ATCK)
+ {
+ if(weapon_prepareattack(0, WEP_CVAR(minelayer, refire)))
+ {
+ W_MineLayer_Attack();
+ weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(minelayer, animtime), w_ready);
+ }
+ }
+
+ if(self.BUTTON_ATCK2)
+ {
+ if(W_MineLayer_PlacedMines(TRUE))
+ sound(self, CH_WEAPON_B, "weapons/mine_det.wav", VOL_BASE, ATTN_NORM);
+ }
+
+ return TRUE;
+ }
+ case WR_INIT:
+ {
+ precache_model("models/flash.md3");
+ precache_model("models/mine.md3");
+ precache_model("models/weapons/g_minelayer.md3");
+ precache_model("models/weapons/v_minelayer.md3");
+ precache_model("models/weapons/h_minelayer.iqm");
+ precache_sound("weapons/mine_det.wav");
+ precache_sound("weapons/mine_fire.wav");
+ precache_sound("weapons/mine_stick.wav");
+ precache_sound("weapons/mine_trigger.wav");
+ MINELAYER_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP)
+ return TRUE;
+ }
+ case WR_CHECKAMMO1:
+ {
+ // don't switch while placing a mine
+ if(ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER)
+ {
+ ammo_amount = self.WEP_AMMO(MINE_LAYER) >= WEP_CVAR(minelayer, ammo);
+ ammo_amount += self.(weapon_load[WEP_MINE_LAYER]) >= WEP_CVAR(minelayer, ammo);
+ return ammo_amount;
+ }
+ return TRUE;
+ }
+ case WR_CHECKAMMO2:
+ {
+ if(W_MineLayer_PlacedMines(FALSE))
+ return TRUE;
+ else
+ return FALSE;
+ }
+ case WR_CONFIG:
+ {
+ MINELAYER_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
+ return TRUE;
+ }
+ case WR_RESETPLAYER:
+ {
+ self.minelayer_mines = 0;
+ return TRUE;
+ }
+ case WR_RELOAD:
+ {
+ W_Reload(WEP_CVAR(minelayer, ammo), "weapons/reload.wav");
+ return TRUE;
+ }
+ case WR_SUICIDEMESSAGE:
+ {
+ return WEAPON_MINELAYER_SUICIDE;
+ }
+ case WR_KILLMESSAGE:
+ {
+ return WEAPON_MINELAYER_MURDER;
+ }
+ }
+ return FALSE;
+ }
+ #endif
+ #ifdef CSQC
+ float W_MineLayer(float req)
+ {
+ switch(req)
+ {
+ case WR_IMPACTEFFECT:
+ {
+ vector org2;
+ org2 = w_org + w_backoff * 12;
+ pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
+ if(!w_issilent)
+ sound(self, CH_SHOTS, "weapons/mine_exp.wav", VOL_BASE, ATTN_NORM);
+
+ return TRUE;
+ }
+ case WR_INIT:
+ {
+ precache_sound("weapons/mine_exp.wav");
+ return TRUE;
+ }
+ case WR_ZOOMRETICLE:
+ {
+ // no weapon specific image for this weapon
+ return FALSE;
+ }
+ }
+ return FALSE;
+ }
+ #endif
+ #endif
--- /dev/null
- centerprint(self.realowner, "^1Portal deployment failed.\n\n^2Catch it to try again!");
+ #ifdef REGISTER_WEAPON
+ REGISTER_WEAPON(
+ /* WEP_##id */ PORTO,
+ /* function */ W_Porto,
+ /* ammotype */ ammo_none,
+ /* impulse */ 0,
+ /* flags */ WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON,
+ /* rating */ 0,
+ /* color */ '0.5 0.5 0.5',
+ /* modelname */ "porto",
+ /* simplemdl */ "foobar",
+ /* crosshair */ "gfx/crosshairporto 0.6",
+ /* wepimg */ "weaponporto",
+ /* refname */ "porto",
+ /* wepname */ _("Port-O-Launch")
+ );
+
+ #define PORTO_SETTINGS(w_cvar,w_prop) PORTO_SETTINGS_LIST(w_cvar, w_prop, PORTO, porto)
+ #define PORTO_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+ w_cvar(id, sn, BOTH, animtime) \
+ w_cvar(id, sn, BOTH, lifetime) \
+ w_cvar(id, sn, BOTH, refire) \
+ w_cvar(id, sn, BOTH, speed) \
+ w_cvar(id, sn, NONE, secondary) \
+ w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \
+ w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \
+ w_prop(id, sn, string, weaponreplace, weaponreplace) \
+ w_prop(id, sn, float, weaponstart, weaponstart) \
+ w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \
+ w_prop(id, sn, float, weaponthrowable, weaponthrowable)
+
+ #ifdef SVQC
+ PORTO_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+ .entity porto_current;
+ .vector porto_v_angle; // holds "held" view angles
+ .float porto_v_angle_held;
+ .vector right_vector;
+ #endif
+ #else
+ #ifdef SVQC
+ void spawnfunc_weapon_porto(void) { weapon_defaultspawnfunc(WEP_PORTO); }
+
+ void W_Porto_Success(void)
+ {
+ if(self.realowner == world)
+ {
+ objerror("Cannot succeed successfully: no owner\n");
+ return;
+ }
+
+ self.realowner.porto_current = world;
+ remove(self);
+ }
+
+ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo);
+ void W_Porto_Fail(float failhard)
+ {
+ if(self.realowner == world)
+ {
+ objerror("Cannot fail successfully: no owner\n");
+ return;
+ }
+
+ // no portals here!
+ if(self.cnt < 0)
+ {
+ Portal_ClearWithID(self.realowner, self.portal_id);
+ }
+
+ self.realowner.porto_current = world;
+
+ if(self.cnt < 0 && !failhard && self.realowner.playerid == self.playerid && self.realowner.deadflag == DEAD_NO && !(self.realowner.weapons & WEPSET_PORTO))
+ {
+ setsize(self, '-16 -16 0', '16 16 32');
+ setorigin(self, self.origin + trace_plane_normal);
+ if(move_out_of_solid(self))
+ {
+ self.flags = FL_ITEM;
+ self.velocity = trigger_push_calculatevelocity(self.origin, self.realowner, 128);
+ tracetoss(self, self);
+ if(vlen(trace_endpos - self.realowner.origin) < 128)
+ {
+ W_ThrowNewWeapon(self.realowner, WEP_PORTO, 0, self.origin, self.velocity);
- centerprint(self.realowner, "^1In^7-portal created.");
++ Send_Notification(NOTIF_ONE, self.realowner, MSG_CENTER, CENTER_PORTO_FAILED);
+ }
+ }
+ }
+ remove(self);
+ }
+
+ void W_Porto_Remove(entity p)
+ {
+ if(p.porto_current.realowner == p && p.porto_current.classname == "porto")
+ {
+ entity oldself;
+ oldself = self;
+ self = p.porto_current;
+ W_Porto_Fail(1);
+ self = oldself;
+ }
+ }
+
+ void W_Porto_Think(void)
+ {
+ trace_plane_normal = '0 0 0';
+ if(self.realowner.playerid != self.playerid)
+ remove(self);
+ else
+ W_Porto_Fail(0);
+ }
+
+ void W_Porto_Touch(void)
+ {
+ vector norm;
+
+ // do not use PROJECTILE_TOUCH here
+ // FIXME but DO handle warpzones!
+
+ if(other.classname == "portal")
+ return; // handled by the portal
+
+ norm = trace_plane_normal;
+ if(trace_ent.iscreature)
+ {
+ traceline(trace_ent.origin, trace_ent.origin + '0 0 2' * PL_MIN_z, MOVE_WORLDONLY, self);
+ if(trace_fraction >= 1)
+ return;
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
+ return;
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ return;
+ }
+
+ if(self.realowner.playerid != self.playerid)
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ remove(self);
+ }
+ else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
+ {
+ spamsound(self, CH_SHOTS, "porto/bounce.wav", VOL_BASE, ATTEN_NORM);
+ // just reflect
+ self.right_vector = self.right_vector - 2 * trace_plane_normal * (self.right_vector * trace_plane_normal);
+ self.angles = vectoangles(self.velocity - 2 * trace_plane_normal * (self.velocity * trace_plane_normal));
+ }
+ else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ W_Porto_Fail(0);
+ if(self.cnt < 0)
+ Portal_ClearAll_PortalsOnly(self.realowner);
+ }
+ else if(self.cnt == 0)
+ {
+ // in-portal only
+ if(Portal_SpawnInPortalAtTrace(self.realowner, self.right_vector, self.portal_id))
+ {
+ sound(self, CH_SHOTS, "porto/create.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
- centerprint(self.realowner, "^4Out^7-portal created.");
++ Send_Notification(NOTIF_ONE, self.realowner, MSG_CENTER, CENTER_PORTO_CREATED_IN);
+ W_Porto_Success();
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
+ W_Porto_Fail(0);
+ }
+ }
+ else if(self.cnt == 1)
+ {
+ // out-portal only
+ if(Portal_SpawnOutPortalAtTrace(self.realowner, self.right_vector, self.portal_id))
+ {
+ sound(self, CH_SHOTS, "porto/create.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
- centerprint(self.realowner, "^1In^7-portal created.");
++ Send_Notification(NOTIF_ONE, self.realowner, MSG_CENTER, CENTER_PORTO_CREATED_OUT);
+ W_Porto_Success();
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
+ W_Porto_Fail(0);
+ }
+ }
+ else if(self.effects & EF_RED)
+ {
+ self.effects += EF_BLUE - EF_RED;
+ if(Portal_SpawnInPortalAtTrace(self.realowner, self.right_vector, self.portal_id))
+ {
+ sound(self, CH_SHOTS, "porto/create.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
- centerprint(self.realowner, "^4Out^7-portal created.");
++ Send_Notification(NOTIF_ONE, self.realowner, MSG_CENTER, CENTER_PORTO_CREATED_IN);
+ self.right_vector = self.right_vector - 2 * trace_plane_normal * (self.right_vector * norm);
+ self.angles = vectoangles(self.velocity - 2 * trace_plane_normal * (self.velocity * norm));
+ CSQCProjectile(self, TRUE, PROJECTILE_PORTO_BLUE, TRUE); // change type
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
+ Portal_ClearAll_PortalsOnly(self.realowner);
+ W_Porto_Fail(0);
+ }
+ }
+ else
+ {
+ if(self.realowner.portal_in.portal_id == self.portal_id)
+ {
+ if(Portal_SpawnOutPortalAtTrace(self.realowner, self.right_vector, self.portal_id))
+ {
+ sound(self, CH_SHOTS, "porto/create.wav", VOL_BASE, ATTEN_NORM);
+ trace_plane_normal = norm;
++ Send_Notification(NOTIF_ONE, self.realowner, MSG_CENTER, CENTER_PORTO_CREATED_OUT);
+ W_Porto_Success();
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ Portal_ClearAll_PortalsOnly(self.realowner);
+ W_Porto_Fail(0);
+ }
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTEN_NORM);
+ Portal_ClearAll_PortalsOnly(self.realowner);
+ W_Porto_Fail(0);
+ }
+ }
+ }
+
+ void W_Porto_Attack(float type)
+ {
+ entity gren;
+
+ W_SetupShot(self, FALSE, 4, "porto/fire.wav", CH_WEAPON_A, 0);
+ // always shoot from the eye
+ w_shotdir = v_forward;
+ w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
+
+ //pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
+
+ gren = spawn();
+ gren.cnt = type;
+ gren.owner = gren.realowner = self;
+ gren.playerid = self.playerid;
+ gren.classname = "porto";
+ gren.bot_dodge = TRUE;
+ gren.bot_dodgerating = 200;
+ gren.movetype = MOVETYPE_BOUNCEMISSILE;
+ PROJECTILE_MAKETRIGGER(gren);
+ gren.effects = EF_RED;
+ gren.scale = 4;
+ setorigin(gren, w_shotorg);
+ setsize(gren, '0 0 0', '0 0 0');
+
+ gren.nextthink = time + WEP_CVAR_BOTH(porto, (type <= 0), lifetime);
+ gren.think = W_Porto_Think;
+ gren.touch = W_Porto_Touch;
+
+ if(self.items & IT_STRENGTH)
+ W_SetupProjVelocity_Basic(gren, WEP_CVAR_BOTH(porto, (type <= 0), speed) * autocvar_g_balance_powerup_strength_force, 0);
+ else
+ W_SetupProjVelocity_Basic(gren, WEP_CVAR_BOTH(porto, (type <= 0), speed), 0);
+
+ gren.angles = vectoangles(gren.velocity);
+ gren.flags = FL_PROJECTILE;
+
+ gren.portal_id = time;
+ self.porto_current = gren;
+ gren.playerid = self.playerid;
+ fixedmakevectors(fixedvectoangles(gren.velocity));
+ gren.right_vector = v_right;
+
+ gren.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
+
+ if(type > 0)
+ CSQCProjectile(gren, TRUE, PROJECTILE_PORTO_BLUE, TRUE);
+ else
+ CSQCProjectile(gren, TRUE, PROJECTILE_PORTO_RED, TRUE);
+
+ other = gren; MUTATOR_CALLHOOK(EditProjectile);
+ }
+
+ float w_nexball_weapon(float req); // WEAPONTODO
+ float W_Porto(float req)
+ {
+ //vector v_angle_save;
+
+ if(g_nexball) { return w_nexball_weapon(req); }
+
+ switch(req)
+ {
+ case WR_AIM:
+ {
+ self.BUTTON_ATCK = FALSE;
+ self.BUTTON_ATCK2 = FALSE;
+ if(!WEP_CVAR(porto, secondary))
+ if(bot_aim(WEP_CVAR_PRI(porto, speed), 0, WEP_CVAR_PRI(porto, lifetime), FALSE))
+ self.BUTTON_ATCK = TRUE;
+
+ return TRUE;
+ }
+ case WR_CONFIG:
+ {
+ PORTO_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
+ return TRUE;
+ }
+ case WR_THINK:
+ {
+ if(WEP_CVAR(porto, secondary))
+ {
+ if(self.BUTTON_ATCK)
+ if(!self.porto_current)
+ if(!self.porto_forbidden)
+ if(weapon_prepareattack(0, WEP_CVAR_PRI(porto, refire)))
+ {
+ W_Porto_Attack(0);
+ weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
+ }
+
+ if(self.BUTTON_ATCK2)
+ if(!self.porto_current)
+ if(!self.porto_forbidden)
+ if(weapon_prepareattack(1, WEP_CVAR_SEC(porto, refire)))
+ {
+ W_Porto_Attack(1);
+ weapon_thinkf(WFRAME_FIRE2, WEP_CVAR_SEC(porto, animtime), w_ready);
+ }
+ }
+ else
+ {
+ if(self.porto_v_angle_held)
+ {
+ if(!self.BUTTON_ATCK2)
+ {
+ self.porto_v_angle_held = 0;
+
+ ClientData_Touch(self);
+ }
+ }
+ else
+ {
+ if(self.BUTTON_ATCK2)
+ {
+ self.porto_v_angle = self.v_angle;
+ self.porto_v_angle_held = 1;
+
+ ClientData_Touch(self);
+ }
+ }
+ if(self.porto_v_angle_held)
+ makevectors(self.porto_v_angle); // override the previously set angles
+
+ if(self.BUTTON_ATCK)
+ if(!self.porto_current)
+ if(!self.porto_forbidden)
+ if(weapon_prepareattack(0, WEP_CVAR_PRI(porto, refire)))
+ {
+ W_Porto_Attack(-1);
+ weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
+ }
+ }
+
+ return TRUE;
+ }
+ case WR_INIT:
+ {
+ precache_model("models/weapons/g_porto.md3");
+ precache_model("models/weapons/v_porto.md3");
+ precache_model("models/weapons/h_porto.iqm");
+ precache_model("models/portal.md3");
+ precache_sound("porto/bounce.wav");
+ precache_sound("porto/create.wav");
+ precache_sound("porto/expire.wav");
+ precache_sound("porto/explode.wav");
+ precache_sound("porto/fire.wav");
+ precache_sound("porto/unsupported.wav");
+ PORTO_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP)
+ return TRUE;
+ }
+ case WR_SETUP:
+ {
+ self.ammo_field = ammo_none;
+ return TRUE;
+ }
+ case WR_RESETPLAYER:
+ {
+ self.porto_current = world;
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ #endif
+ #ifdef CSQC
+ float W_Porto(float req)
+ {
+ switch(req)
+ {
+ case WR_IMPACTEFFECT:
+ {
+ print("Since when does Porto send DamageInfo?\n");
+ return TRUE;
+ }
+ case WR_INIT:
+ {
+ // nothing to do
+ return TRUE;
+ }
+ case WR_ZOOMRETICLE:
+ {
+ // no weapon specific image for this weapon
+ return FALSE;
+ }
+ }
+ return FALSE;
+ }
+ #endif
+ #endif
void player_regen (void)
{
- float minh, mina, minf, maxh, maxa, maxf, limith, limita, limitf, max_mod, regen_mod, rot_mod, limit_mod;
- maxh = autocvar_g_balance_health_rotstable;
- maxa = autocvar_g_balance_armor_rotstable;
- maxf = autocvar_g_balance_fuel_rotstable;
- minh = autocvar_g_balance_health_regenstable;
- mina = autocvar_g_balance_armor_regenstable;
- minf = autocvar_g_balance_fuel_regenstable;
- limith = autocvar_g_balance_health_limit;
- limita = autocvar_g_balance_armor_limit;
- limitf = autocvar_g_balance_fuel_limit;
-
+ float max_mod, regen_mod, rot_mod, limit_mod;
max_mod = regen_mod = rot_mod = limit_mod = 1;
-
+ regen_mod_max = max_mod;
+ regen_mod_regen = regen_mod;
+ regen_mod_rot = rot_mod;
+ regen_mod_limit = limit_mod;
+ if(!MUTATOR_CALLHOOK(PlayerRegen))
+ if(!self.frozen)
+ {
+ float minh, mina, maxh, maxa, limith, limita;
+ maxh = autocvar_g_balance_health_rotstable;
+ maxa = autocvar_g_balance_armor_rotstable;
+ minh = autocvar_g_balance_health_regenstable;
+ mina = autocvar_g_balance_armor_regenstable;
+ limith = autocvar_g_balance_health_limit;
+ limita = autocvar_g_balance_armor_limit;
++
+ max_mod = regen_mod_max;
+ regen_mod = regen_mod_regen;
+ rot_mod = regen_mod_rot;
+ limit_mod = regen_mod_limit;
+
+ maxh = maxh * max_mod;
+ minh = minh * max_mod;
+ limith = limith * limit_mod;
+ limita = limita * limit_mod;
- maxh = maxh * max_mod;
- //maxa = maxa * max_mod;
- //maxf = maxf * max_mod;
- minh = minh * max_mod;
- //mina = mina * max_mod;
- //minf = minf * max_mod;
- limith = limith * limit_mod;
- limita = limita * limit_mod;
- //limitf = limitf * limit_mod;
+ self.armorvalue = CalcRotRegen(self.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > self.pauserotarmor_finished), limita);
+ self.health = CalcRotRegen(self.health, minh, autocvar_g_balance_health_regen, autocvar_g_balance_health_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxh, autocvar_g_balance_health_rot, autocvar_g_balance_health_rotlinear, rot_mod * frametime * (time > self.pauserothealth_finished), limith);
+ }
- if(g_ca)
- rot_mod = 0;
+ // if player rotted to death... die!
+ // check this outside above checks, as player may still be able to rot to death
+ if(self.health < 1)
+ self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
- if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
+ if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
{
- self.armorvalue = CalcRotRegen(self.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > self.pauserotarmor_finished), limita);
- self.health = CalcRotRegen(self.health, minh, autocvar_g_balance_health_regen, autocvar_g_balance_health_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished), maxh, autocvar_g_balance_health_rot, autocvar_g_balance_health_rotlinear, rot_mod * frametime * (time > self.pauserothealth_finished), limith);
+ float minf, maxf, limitf;
- // if player rotted to death... die!
- if(self.health < 1)
- self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
- }
+ maxf = autocvar_g_balance_fuel_rotstable;
+ minf = autocvar_g_balance_fuel_regenstable;
+ limitf = autocvar_g_balance_fuel_limit;
- if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
- self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, regen_mod * frametime * (time > self.pauseregen_finished) * ((self.items & IT_FUEL_REGEN) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, rot_mod * frametime * (time > self.pauserotfuel_finished), limitf);
+ self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & IT_FUEL_REGEN) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
+ }
}
float zoomstate_set;
return 1;
}
--
float SpectateSet()
{
if(self.enemy.classname != "player")
}
*/
-- //pointparticles(particleeffectnum("machinegun_impact"), self.origin + self.view_ofs + '0 0 7', '0 0 0', 1);
--
if(self.waypointsprite_attachedforcarrier)
WaypointSprite_UpdateHealth(self.waypointsprite_attachedforcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
{
if(IS_CLIENT(self))
{
- if(!IS_PLAYER(self) && !lockteams && !g_arena)
- if(!IS_PLAYER(self) && !lockteams)
++ if(!IS_PLAYER(self) && !lockteams && !gameover)
{
- if(nJoinAllowed(self))
+ if(self.caplayer)
+ return;
+ if(nJoinAllowed(self))
{
if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
else if(self.wasplayer && autocvar_g_changeteam_banned)
sprint(self, "^1You cannot change team, forbidden by the server.\n");
else
- sprint(self, "Cannot change to a larger/better/shinier team\n");
+ {
+ if(autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
+ {
+ CheckAllowedTeams(self);
+ GetTeamCounts(self);
+ if(!TeamSmallerEqThanTeam(Team_TeamToNumber(selection), Team_TeamToNumber(self.team), self))
+ {
++ Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
+ return;
+ }
+ }
ClientKill_TeamChange(selection);
+ }
}
}
else
{
case CMD_REQUEST_COMMAND:
{
- entity client;
- string result1 = (argv(2) ? strcat("^7", argv(1), "^3!\n") : "^1HEADS^3!\n");
- string result2 = (argv(2) ? strcat("^7", argv(2), "^3!\n") : "^4TAILS^3!\n");
+ string result1 = (argv(2) ? strcat("^7", argv(1)) : "^1HEADS");
+ string result2 = (argv(2) ? strcat("^7", argv(2)) : "^4TAILS");
string choice = ((random() > 0.5) ? result1 : result2);
-
- FOR_EACH_CLIENT(client)
- centerprint(client, strcat("^3Throwing coin... Result: ", choice));
- bprint(strcat("^3Throwing coin... Result: ", choice));
+
+ Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_COINTOSS, choice);
-
return;
}
-
+
default:
case CMD_REQUEST_USAGE:
{
} else if (other.key_door_messagetime <= time) {
// no keys were given
play2(other, self.noise2);
- centerprint(other, strcat("You need ", item_keys_keylist(self.itemkeys), "!"));
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(self.itemkeys));
other.key_door_messagetime = time + 2;
}
-
+
// trigger target2
if (self.delay <= time || started_delay == TRUE)
if (self.target2) {
MUTATOR_HOOKFUNCTION(assault_PlayerSpawn)
{
if(self.team == assault_attacker_team)
- centerprint(self, "You are attacking!");
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
else
- centerprint(self, "You are defending!");
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
-
+
return FALSE;
}