From: Mario Date: Tue, 2 Dec 2014 02:21:16 +0000 (+1100) Subject: Merge branch 'master' into Mario/turrets X-Git-Tag: xonotic-v0.8.2~2052^2~6 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=ac5366add2c2d44bff2e03fc916b991eb009a10a;hp=-c;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into Mario/turrets Conflicts: qcsrc/server/progs.src qcsrc/server/tturrets/units/unit_plasma.qc --- ac5366add2c2d44bff2e03fc916b991eb009a10a diff --combined qcsrc/client/Main.qc index 077bc0590,c0e37ae62..997427ff5 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@@ -87,6 -87,9 +87,9 @@@ void CSQC_Init(void registercvar("hud_usecsqc", "1"); registercvar("scoreboard_columns", "default"); + registercvar("cl_nade_type", "3"); + registercvar("cl_pokenade_type", "zombie"); + gametype = 0; // hud_fields uses strunzone on the titles! @@@ -104,12 -107,12 +107,13 @@@ // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterTurrets); CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); WaypointSprite_Load(); @@@ -124,6 -127,7 +128,6 @@@ Casings_Precache(); DamageInfo_Precache(); Vehicles_Precache(); - turrets_precache(); Tuba_Precache(); CSQCPlayer_Precache(); @@@ -214,7 -218,7 +218,7 @@@ float SetTeam(entity o, float Team default: if(GetTeam(Team, false) == world) { - printf(_("trying to switch to unsupported team %d\n"), Team); + dprintf("trying to switch to unsupported team %d\n", Team); Team = NUM_SPECTATOR; } break; @@@ -230,7 -234,7 +234,7 @@@ default: if(GetTeam(Team, false) == world) { - printf(_("trying to switch to unsupported team %d\n"), Team); + dprintf("trying to switch to unsupported team %d\n", Team); Team = NUM_SPECTATOR; } break; @@@ -830,6 -834,7 +834,7 @@@ void CSQC_Ent_Update(float bIsNewEntity case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break; case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break; case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break; + case ENT_CLIENT_HEALING_ORB: ent_healer(); break; default: //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); diff --combined qcsrc/client/progs.src index a5109ac69,86a8b4339..7f284a8d7 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@@ -8,6 -8,7 +8,7 @@@ sys-post.q Defs.qc ../dpdefs/keycodes.qc ../common/constants.qh + ../common/stats.qh ../warpzonelib/anglestransform.qh ../warpzonelib/mathlib.qh @@@ -16,6 -17,8 +17,8 @@@ ../common/teams.qh ../common/util.qh + ../common/nades.qh + ../common/buffs.qh ../common/test.qh ../common/counting.qh ../common/items.qh @@@ -36,9 -39,6 +39,9 @@@ autocvars.q ../common/notifications.qh // must be after autocvars ../common/deathtypes.qh // must be after notifications +../common/turrets/turrets.qh +../common/turrets/cl_turrets.qh + damage.qh ../csqcmodellib/interpolate.qh @@@ -50,6 -50,8 +53,6 @@@ movetypes.q prandom.qh bgmscript.qh noise.qh -tturrets.qh -../server/tturrets/include/turrets_early.qh ../server/movelib.qc main.qh vehicles/vehicles.qh @@@ -118,13 -120,14 +121,16 @@@ command/cl_cmd.q ../common/monsters/monsters.qc + ../common/nades.qc + ../common/buffs.qc + ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc ../warpzonelib/common.qc ../warpzonelib/client.qc -tturrets.qc + +../common/turrets/cl_turrets.qc +../common/turrets/turrets.qc player_skeleton.qc ../common/animdecide.qc diff --combined qcsrc/common/deathtypes.qh index 92a20e154,c8512cdcf..602966cb3 --- a/qcsrc/common/deathtypes.qh +++ b/qcsrc/common/deathtypes.qh @@@ -4,6 -4,7 +4,7 @@@ #define DEATHTYPES \ DEATHTYPE(DEATH_AUTOTEAMCHANGE, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, DEATH_SPECIAL_START) \ + DEATHTYPE(DEATH_BUFF_VENGEANCE, NO_MSG, DEATH_MURDER_VENGEANCE, NORMAL_POS) \ DEATHTYPE(DEATH_CAMP, DEATH_SELF_CAMP, NO_MSG, NORMAL_POS) \ DEATHTYPE(DEATH_CHEAT, DEATH_SELF_CHEAT, DEATH_MURDER_CHEAT, NORMAL_POS) \ DEATHTYPE(DEATH_CUSTOM, DEATH_SELF_CUSTOM, NO_MSG, NORMAL_POS) \ @@@ -23,7 -24,11 +24,11 @@@ DEATHTYPE(DEATH_MONSTER_WYVERN, DEATH_SELF_MON_WYVERN, DEATH_MURDER_MONSTER, NORMAL_POS) \ DEATHTYPE(DEATH_MONSTER_ZOMBIE_JUMP, DEATH_SELF_MON_ZOMBIE_JUMP, DEATH_MURDER_MONSTER, NORMAL_POS) \ DEATHTYPE(DEATH_MONSTER_ZOMBIE_MELEE, DEATH_SELF_MON_ZOMBIE_MELEE, DEATH_MURDER_MONSTER, DEATH_MONSTER_LAST) \ - DEATHTYPE(DEATH_NADE, DEATH_SELF_NADE, DEATH_MURDER_NADE, NORMAL_POS) \ + DEATHTYPE(DEATH_NADE, DEATH_SELF_NADE, DEATH_MURDER_NADE, NORMAL_POS) \ + DEATHTYPE(DEATH_NADE_NAPALM, DEATH_SELF_NADE_NAPALM, DEATH_MURDER_NADE_NAPALM, NORMAL_POS) \ + DEATHTYPE(DEATH_NADE_ICE, DEATH_SELF_NADE_ICE, DEATH_MURDER_NADE_ICE, NORMAL_POS) \ + DEATHTYPE(DEATH_NADE_ICE_FREEZE, DEATH_SELF_NADE_ICE_FREEZE, DEATH_MURDER_NADE_ICE_FREEZE, NORMAL_POS) \ + DEATHTYPE(DEATH_NADE_HEAL, DEATH_SELF_NADE_HEAL, DEATH_MURDER_NADE_HEAL, NORMAL_POS) \ DEATHTYPE(DEATH_NOAMMO, DEATH_SELF_NOAMMO, NO_MSG, NORMAL_POS) \ DEATHTYPE(DEATH_ROT, DEATH_SELF_ROT, NO_MSG, NORMAL_POS) \ DEATHTYPE(DEATH_SHOOTING_STAR, DEATH_SELF_SHOOTING_STAR, DEATH_MURDER_SHOOTING_STAR, NORMAL_POS) \ @@@ -43,7 -48,7 +48,7 @@@ DEATHTYPE(DEATH_TURRET_PLASMA, DEATH_SELF_TURRET_PLASMA, NO_MSG, NORMAL_POS) \ DEATHTYPE(DEATH_TURRET_TESLA, DEATH_SELF_TURRET_TESLA, NO_MSG, NORMAL_POS) \ DEATHTYPE(DEATH_TURRET_WALK_GUN, DEATH_SELF_TURRET_WALK_GUN, NO_MSG, NORMAL_POS) \ - DEATHTYPE(DEATH_TURRET_WALK_MEELE, DEATH_SELF_TURRET_WALK_MEELE, NO_MSG, NORMAL_POS) \ + DEATHTYPE(DEATH_TURRET_WALK_MELEE, DEATH_SELF_TURRET_WALK_MELEE, NO_MSG, NORMAL_POS) \ DEATHTYPE(DEATH_TURRET_WALK_ROCKET, DEATH_SELF_TURRET_WALK_ROCKET, NO_MSG, DEATH_TURRET_LAST) \ DEATHTYPE(DEATH_VH_BUMB_DEATH, DEATH_SELF_VH_BUMB_DEATH, DEATH_MURDER_VH_BUMB_DEATH, DEATH_VHFIRST) \ DEATHTYPE(DEATH_VH_BUMB_GUN, NO_MSG, DEATH_MURDER_VH_BUMB_GUN, NORMAL_POS) \ diff --combined qcsrc/common/notifications.qh index 2b5576073,b45c648f7..85785bf65 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@@ -248,9 -248,9 +248,9 @@@ void Send_Notification_WOCOVA MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_20, CH_INFO, "20kills", VOL_BASEVOICE, ATTEN_NONE) \ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_25, CH_INFO, "25kills", VOL_BASEVOICE, ATTEN_NONE) \ MSG_ANNCE_NOTIF(1, ANNCE_KILLSTREAK_30, CH_INFO, "30kills", VOL_BASEVOICE, ATTEN_NONE) \ - MSG_ANNCE_NOTIF(1, ANNCE_MINSTAGIB_LASTSECOND, CH_INFO, "lastsecond", VOL_BASEVOICE, ATTEN_NONE) \ - MSG_ANNCE_NOTIF(1, ANNCE_MINSTAGIB_NARROWLY, CH_INFO, "narrowly", VOL_BASEVOICE, ATTEN_NONE) \ - MSG_ANNCE_NOTIF(1, ANNCE_MINSTAGIB_TERMINATED, CH_INFO, "terminated", VOL_BASEVOICE, ATTEN_NONE) \ + MSG_ANNCE_NOTIF(1, ANNCE_INSTAGIB_LASTSECOND, CH_INFO, "lastsecond", VOL_BASEVOICE, ATTEN_NONE) \ + MSG_ANNCE_NOTIF(1, ANNCE_INSTAGIB_NARROWLY, CH_INFO, "narrowly", VOL_BASEVOICE, ATTEN_NONE) \ + MSG_ANNCE_NOTIF(1, ANNCE_INSTAGIB_TERMINATED, CH_INFO, "terminated", VOL_BASEVOICE, ATTEN_NONE) \ MSG_ANNCE_NOTIF(0, ANNCE_MULTIFRAG, CH_INFO, "multifrag", VOL_BASEVOICE, ATTEN_NONE) \ MSG_ANNCE_NOTIF(2, ANNCE_NUM_1, CH_INFO, "1", VOL_BASEVOICE, ATTEN_NONE) \ MSG_ANNCE_NOTIF(2, ANNCE_NUM_2, CH_INFO, "2", VOL_BASEVOICE, ATTEN_NONE) \ @@@ -360,7 -360,11 +360,11 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FIRE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"), _("^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s")) \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_LAVA, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_lava", _("^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_MONSTER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was pushed infront of a monster by ^BG%s^K1%s%s"), "") \ - MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_NAPALM, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_napalm", _("^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"), _("^BG%s%s^K1 got too close to a napalm explosion%s%s")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_ICE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_ice", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_ICE_FREEZE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_ice", _("^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_HEAL, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_heal", _("^BG%s%s^K1 has not been healed by ^BG%s^K1's Healing Nade%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SHOOTING_STAR, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_shootingstar", _("^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SLIME, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was slimed by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SWAMP, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was preserved by ^BG%s^K1%s%s"), "") \ @@@ -378,6 -382,7 +382,7 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_GUN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_ROCKET, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VENGEANCE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was destroyed by the vengeful ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VOID, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_void", _("^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_AUTOTEAMCHANGE, 2, 1, "s1 s2loc death_team", "", "", _("^BG%s^K1 was moved into the %s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_BETRAYAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_teamkill_red", _("^BG%s^K1 became enemies with the Lord of Teamplay%s%s"), "") \ @@@ -389,7 -394,6 +394,6 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_FIRE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 became a bit too crispy%s%s"), _("^BG%s^K1 felt a little hot%s%s")) \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_GENERIC, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 died%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_LAVA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_lava", _("^BG%s^K1 turned into hot slag%s%s"), _("^BG%s^K1 found a hot place%s%s")) \ - MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_MAGE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was exploded by a Mage%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_SHAMBLER_CLAW, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1's innards became outwards by a Shambler%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_SHAMBLER_SMASH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was smashed by a Shambler%s%s"), "") \ @@@ -398,6 -402,11 +402,11 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_WYVERN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was fireballed by a Wyvern%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 joins the Zombies%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_ZOMBIE_MELEE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was given kung fu lessons by a Zombie%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_NAPALM, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_napalm", _("^BG%s^K1 was burned to death by their own Napalm Nade%s%s"), _("^BG%s^K1 decided to take a look at the results of their napalm explosion%s%s")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_ICE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_ice", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_ICE_FREEZE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_ice", _("^BG%s^K1 was frozen to death by their own Ice Nade%s%s"), _("^BG%s^K1 felt a little chilly%s%s")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_HEAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_heal", _("^BG%s^K1's Healing Nade didn't quite heal them%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NOAMMO, 2, 1, "s1 s2loc spree_lost", "s1", "notify_outofammo", _("^BG%s^K1 died%s%s. What's the point of living without ammo?"), _("^BG%s^K1 ran out of ammo%s%s")) \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_ROT, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 rotted away%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SHOOTING_STAR, 2, 1, "s1 s2loc spree_lost", "s1", "notify_shootingstar", _("^BG%s^K1 became a shooting star%s%s"), "") \ @@@ -417,7 -426,7 +426,7 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_PLASMA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got served some superheated plasma from a turret%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_TESLA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was electrocuted by a Tesla turret%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_GUN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got served a lead enrichment by a Walker turret%s%s"), "") \ - MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_MEELE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was impaled by a Walker turret%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_MELEE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was impaled by a Walker turret%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_TURRET_WALK_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was blasted away by a Walker turret%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_BUMB_DEATH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 got caught in the blast of a Bumblebee explosion%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_CRUSH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was crushed by a vehicle%s%s"), "") \ @@@ -429,9 -438,11 +438,11 @@@ 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_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_FREEZETAG_REVIVED_NADE, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by their Nade explosion"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_AUTO_REVIVED, 1, 1, "s1 f1", "", "", _("^BG%s^K3 was automatically revived after %s second(s)"), "") \ MULTITEAM_INFO(1, INFO_ROUND_TEAM_WIN_, 4, 0, 0, "", "", "", _("^TC^TT^BG team wins the round"), "") \ MSG_INFO_NOTIF(1, INFO_ROUND_PLAYER_WIN, 1, 0, "s1", "", "", _("^BG%s^BG wins the round"), "") \ @@@ -439,6 -450,10 +450,10 @@@ MSG_INFO_NOTIF(1, INFO_ROUND_OVER, 0, 0, "", "", "", _("^BGRound over, there's no winner"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_SELF, 1, 0, "s1", "", "", _("^BG%s^K1 froze themself"), "") \ MSG_INFO_NOTIF(1, INFO_GODMODE_OFF, 0, 1, "f1", "", "", _("^BGGodmode saved you %s units of damage, cheater!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG got the %s^BG Buff!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_LOST, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG lost the %s^BG Buff!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_DROP, 0, 1, "item_buffname", "", "", _("^BGYou dropped the %s^BG Buff!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_GOT, 0, 1, "item_buffname", "", "", _("^BGYou got the %s^BG Buff!"), "") \ MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", "", "", _("^BGYou do not have the ^F1%s"), "") \ MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", "", "", _("^BGYou dropped the ^F1%s^BG%s"), "") \ MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_GOT, 0, 1, "item_wepname", "", "", _("^BGYou got the ^F1%s"), "") \ @@@ -475,7 -490,9 +490,9 @@@ MSG_INFO_NOTIF(1, INFO_RACE_NEW_SET, 1, 2, "s1 race_col f1ord race_col f2race_time", "s1 f2race_time", "race_newrecordserver", _("^BG%s^BG set the %s%s^BG place record with %s%s"), "") \ MULTITEAM_INFO(1, INFO_SCORES_, 4, 0, 0, "", "", "", _("^TC^TT ^BGteam scores!"), "") \ MSG_INFO_NOTIF(1, INFO_SPECTATE_WARNING, 0, 1, "f1secs", "", "", _("^F2You have to become a player within the next %s, otherwise you will be kicked, because spectating isn't allowed at this time!"), "") \ - MSG_INFO_NOTIF(1, INFO_SUPERWEAPON_PICKUP, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up a Superweapon"), "") \ + MSG_INFO_NOTIF(1, INFO_SUPERWEAPON_PICKUP, 1, 0, "s1", "s1", "superweapons", _("^BG%s^K1 picked up a Superweapon"), "") \ + MSG_INFO_NOTIF(1, INFO_TEAMCHANGE_LARGERTEAM, 0, 0, "", "", "", _("^BGYou cannot change to a larger team"), "") \ + MSG_INFO_NOTIF(1, INFO_TEAMCHANGE_NOTALLOWED, 0, 0, "", "", "", _("^BGYou are not allowed to change teams"), "") \ MSG_INFO_NOTIF(2, INFO_VERSION_BETA, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s"), "") \ MSG_INFO_NOTIF(2, INFO_VERSION_OLD, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"), "") \ MSG_INFO_NOTIF(2, INFO_VERSION_OUTDATED, 2, 0, "s1 s2", "", "", _("^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get the update from ^F3http://www.xonotic.org/^BG!"), "") \ @@@ -580,6 -597,7 +597,7 @@@ MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, 1, 4, "spree_cen s1 frag_stats", NO_CPID, "0 0", _("^K1%sYou were typefragged by ^BG%s^BG%s"), _("^K1%sYou were scored against by ^BG%s^K1 while typing^BG%s")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, 1, 2, "spree_cen s1 frag_ping", NO_CPID, "0 0", _("^K1%sYou typefragged ^BG%s^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing^BG%s")) \ MSG_CENTER_NOTIF(1, CENTER_NADE_THROW, 0, 0, "", CPID_NADES, "0 0", _("^BGPress ^F2DROPWEAPON^BG again to toss the nade!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_NADE_BONUS, 0, 0, "", CPID_NADES, "0 0", _("^F2You got a ^K1BONUS GRENADE^F2!"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_AUTOTEAMCHANGE, 0, 1, "death_team", NO_CPID, "0 0", _("^BGYou have been moved into a different team\nYou are now on: %s"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_BETRAYAL, 0, 0, "", NO_CPID, "0 0", _("^K1Don't shoot your team mates!"), _("^K1Don't go against your team mates!")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_CAMP, 0, 0, "", NO_CPID, "0 0", _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \ @@@ -592,6 -610,9 +610,9 @@@ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_LAVA, 0, 0, "", NO_CPID, "0 0", _("^K1You couldn't stand the heat!"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_MONSTER, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed by a monster!"), _("^K1You need to watch out for monsters!")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE, 0, 0, "", NO_CPID, "0 0", _("^K1You forgot to put the pin back in!"), _("^K1Tastes like chicken!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_NAPALM, 0, 0, "", NO_CPID, "0 0", _("^K1Hanging around a napalm explosion is bad!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_ICE_FREEZE, 0, 0, "", NO_CPID, "0 0", _("^K1You got a little bit too cold!"), _("^K1You felt a little chilly!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_HEAL, 0, 0, "", NO_CPID, "0 0", _("^K1Your Healing Nade is a bit defective"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NOAMMO, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed for running out of ammo..."), _("^K1You are respawning for running out of ammo...")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_ROT, 0, 0, "", NO_CPID, "0 0", _("^K1You grew too old without taking your medicine"), _("^K1You need to preserve your health")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SHOOTING_STAR, 0, 0, "", NO_CPID, "0 0", _("^K1You became a shooting star!"), "") \ @@@ -615,11 -636,14 +636,14 @@@ MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAG, 1, 0, "s1", NO_CPID, "0 0", _("^K1Moron! You fragged ^BG%s^K1, a team mate!"), _("^K1Moron! You went against ^BG%s^K1, a team mate!")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAGGED, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were fragged by ^BG%s^K1, a team mate"), _("^K1You were scored against by ^BG%s^K1, a team mate")) \ MSG_CENTER_NOTIF(1, CENTER_DISCONNECT_IDLING, 0, 1, "", CPID_IDLING, "1 f1", _("^K1Stop idling!\n^BGDisconnecting in ^COUNT..."), "") \ + MSG_CENTER_NOTIF(1, CENTER_DOOR_LOCKED_NEED, 0, 0, "", NO_CPID, "0 0", _("^BGYou need %s^BG!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DOOR_LOCKED_ALSONEED, 0, 0, "", NO_CPID, "0 0", _("^BGYou also need %s^BG!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DOOR_UNLOCKED, 0, 0, "", NO_CPID, "0 0", _("^BGDoor unlocked!"), "") \ MSG_CENTER_NOTIF(1, CENTER_EXTRALIVES, 0, 0, "", NO_CPID, "0 0", _("^F2You picked up some extra lives"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FREEZE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You froze ^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FROZEN, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were frozen by ^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You revived ^BG%s"), "") \ - MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_FALL, 0, 0, "", NO_CPID, "0 0", _("^K3You revived yourself"), "") \ + MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_SELF, 0, 0, "", NO_CPID, "0 0", _("^K3You revived yourself"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVED, 1, 0, "s1", NO_CPID, "0 0", _("^K3You were revived by ^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_AUTO_REVIVED, 0, 1, "f1", NO_CPID, "0 0", _("^K3You were automatically revived after %s second(s)"), "") \ MULTITEAM_CENTER(1, CENTER_ROUND_TEAM_WIN_, 4, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team wins the round"), "") \ @@@ -627,6 -651,8 +651,8 @@@ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SELF, 0, 0, "", NO_CPID, "0 0", _("^K1You froze yourself"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SPAWN_LATE, 0, 0, "", NO_CPID, "0 0", _("^K1Round already started, you spawn as frozen"), "") \ MSG_CENTER_NOTIF(1, CENTER_INVASION_SUPERMONSTER, 1, 0, "s1", NO_CPID, "0 0", _("^K1A %s has arrived!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_ITEM_BUFF_DROP, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou dropped the %s^BG Buff!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_ITEM_BUFF_GOT, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou got the %s^BG Buff!"), "") \ MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_GOT, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%s"), "") \ @@@ -637,6 -663,7 +663,7 @@@ MSG_CENTER_NOTIF(1, CENTER_JOIN_PREVENT, 0, 0, "", CPID_PREVENT_JOIN, "0 0", _("^K1You may not join the game at this time.\nThe player limit reached maximum capacity."), "") \ MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_DROPPED, 1, 0, "s1", CPID_KEEPAWAY, "0 0", _("^BG%s^BG has dropped the ball!"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_PICKUP, 1, 0, "s1", CPID_KEEPAWAY, "0 0", _("^BG%s^BG has picked up the ball!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_PICKUP_SELF, 0, 0, "", CPID_KEEPAWAY, "0 0", _("^BGYou picked up the ball"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_WARN, 0, 0, "", CPID_KEEPAWAY_WARN, "0 0", _("^BGKilling people while you don't have the ball gives no points!"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_HELP, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in your team's hands!\nHelp the key carriers to meet!"), "") \ MULTITEAM_CENTER(1, CENTER_KEYHUNT_INTERFERE_, 4, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in ^TC^TT team^BG's hands!\nInterfere ^F4NOW^BG!"), "") \ @@@ -666,6 -693,9 +693,9 @@@ MSG_CENTER_NOTIF(1, CENTER_POWERUP_SPEED, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You are on speed"), "") \ MSG_CENTER_NOTIF(1, CENTER_POWERUP_STRENGTH, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Strength infuses your weapons with devastating power"), "") \ MSG_CENTER_NOTIF(1, CENTER_RACE_FINISHLAP, 0, 0, "", CPID_RACE_FINISHLAP, "0 0", _("^F2The race is over, finish your lap!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_SEQUENCE_COMPLETED, 0, 0, "", NO_CPID, "0 0", _("^BGSequence completed!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_SEQUENCE_COUNTER, 0, 0, "", NO_CPID, "0 0", _("^BGThere are more to go..."), "") \ + MSG_CENTER_NOTIF(1, CENTER_SEQUENCE_COUNTER_FEWMORE, 0, 1, "f1", NO_CPID, "0 0", _("^BGOnly %s^BG more to go..."), "") \ MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_BROKEN, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have broken down"), "") \ MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_LOST, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have been lost"), "") \ MSG_CENTER_NOTIF(1, CENTER_SUPERWEAPON_PICKUP, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You now have a superweapon"), "") \ @@@ -699,6 -729,10 +729,10 @@@ MSG_MULTI_NOTIF(1, DEATH_MURDER_LAVA, NO_MSG, INFO_DEATH_MURDER_LAVA, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_MONSTER, NO_MSG, INFO_DEATH_MURDER_MONSTER, CENTER_DEATH_SELF_MONSTER) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE, NO_MSG, INFO_DEATH_MURDER_NADE, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_NAPALM, NO_MSG, INFO_DEATH_MURDER_NADE_NAPALM, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_ICE, NO_MSG, INFO_DEATH_MURDER_NADE_ICE, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_ICE_FREEZE, NO_MSG, INFO_DEATH_MURDER_NADE_ICE_FREEZE, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_HEAL, NO_MSG, INFO_DEATH_MURDER_NADE_HEAL, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_SHOOTING_STAR, NO_MSG, INFO_DEATH_MURDER_SHOOTING_STAR, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_SLIME, NO_MSG, INFO_DEATH_MURDER_SLIME, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_SWAMP, NO_MSG, INFO_DEATH_MURDER_SWAMP, NO_MSG) \ @@@ -716,6 -750,7 +750,7 @@@ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_DEATH, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_GUN, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_GUN, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_VENGEANCE, NO_MSG, INFO_DEATH_MURDER_VENGEANCE, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_VOID, NO_MSG, INFO_DEATH_MURDER_VOID, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \ MSG_MULTI_NOTIF(1, DEATH_SELF_BETRAYAL, NO_MSG, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \ @@@ -736,6 -771,10 +771,10 @@@ MSG_MULTI_NOTIF(1, DEATH_SELF_MON_ZOMBIE_JUMP, NO_MSG, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, CENTER_DEATH_SELF_MONSTER) \ MSG_MULTI_NOTIF(1, DEATH_SELF_MON_ZOMBIE_MELEE, NO_MSG, INFO_DEATH_SELF_MON_ZOMBIE_MELEE, CENTER_DEATH_SELF_MONSTER) \ MSG_MULTI_NOTIF(1, DEATH_SELF_NADE, NO_MSG, INFO_DEATH_SELF_NADE, CENTER_DEATH_SELF_NADE) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_NAPALM, NO_MSG, INFO_DEATH_SELF_NADE_NAPALM, CENTER_DEATH_SELF_NADE_NAPALM) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_ICE, NO_MSG, INFO_DEATH_SELF_NADE_ICE, CENTER_DEATH_SELF_NADE_ICE_FREEZE) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_ICE_FREEZE, NO_MSG, INFO_DEATH_SELF_NADE_ICE_FREEZE, CENTER_DEATH_SELF_NADE_ICE_FREEZE) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_HEAL, NO_MSG, INFO_DEATH_SELF_NADE_HEAL, CENTER_DEATH_SELF_NADE_HEAL) \ MSG_MULTI_NOTIF(1, DEATH_SELF_NOAMMO, NO_MSG, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \ MSG_MULTI_NOTIF(1, DEATH_SELF_ROT, NO_MSG, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \ MSG_MULTI_NOTIF(1, DEATH_SELF_SHOOTING_STAR, NO_MSG, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \ @@@ -755,7 -794,7 +794,7 @@@ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_PLASMA, NO_MSG, INFO_DEATH_SELF_TURRET_PLASMA, CENTER_DEATH_SELF_TURRET) \ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_TESLA, NO_MSG, INFO_DEATH_SELF_TURRET_TESLA, CENTER_DEATH_SELF_TURRET) \ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_GUN, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_GUN, CENTER_DEATH_SELF_TURRET_WALK) \ - MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_MEELE, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_MEELE, CENTER_DEATH_SELF_TURRET_WALK) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_MELEE, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_MELEE, CENTER_DEATH_SELF_TURRET_WALK) \ MSG_MULTI_NOTIF(1, DEATH_SELF_TURRET_WALK_ROCKET, NO_MSG, INFO_DEATH_SELF_TURRET_WALK_ROCKET, CENTER_DEATH_SELF_TURRET_WALK) \ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_BUMB_DEATH, NO_MSG, INFO_DEATH_SELF_VH_BUMB_DEATH, CENTER_DEATH_SELF_VH_BUMB_DEATH) \ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_CRUSH, NO_MSG, INFO_DEATH_SELF_VH_CRUSH, CENTER_DEATH_SELF_VH_CRUSH) \ @@@ -766,6 -805,8 +805,8 @@@ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_SELF_VH_WAKI_DEATH, CENTER_DEATH_SELF_VH_WAKI_DEATH) \ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_SELF_VH_WAKI_ROCKET, CENTER_DEATH_SELF_VH_WAKI_ROCKET) \ MSG_MULTI_NOTIF(1, DEATH_SELF_VOID, NO_MSG, INFO_DEATH_SELF_VOID, CENTER_DEATH_SELF_VOID) \ + MSG_MULTI_NOTIF(1, ITEM_BUFF_DROP, NO_MSG, INFO_ITEM_BUFF_DROP, CENTER_ITEM_BUFF_DROP) \ + MSG_MULTI_NOTIF(1, ITEM_BUFF_GOT, NO_MSG, INFO_ITEM_BUFF_GOT, CENTER_ITEM_BUFF_GOT) \ MSG_MULTI_NOTIF(1, ITEM_WEAPON_DONTHAVE, NO_MSG, INFO_ITEM_WEAPON_DONTHAVE, CENTER_ITEM_WEAPON_DONTHAVE) \ MSG_MULTI_NOTIF(1, ITEM_WEAPON_DROP, NO_MSG, INFO_ITEM_WEAPON_DROP, CENTER_ITEM_WEAPON_DROP) \ MSG_MULTI_NOTIF(1, ITEM_WEAPON_GOT, NO_MSG, INFO_ITEM_WEAPON_GOT, CENTER_ITEM_WEAPON_GOT) \ @@@ -933,6 -974,7 +974,7 @@@ var float autocvar_notification_show_sp item_wepname: return full name of a weapon from weaponid item_wepammo: ammo display for weapon from string item_centime: amount of time to display weapon message in centerprint + item_buffname: return full name of a buff from buffid death_team: show the full name of the team a player is switching from */ @@@ -985,6 -1027,7 +1027,7 @@@ string arg_slot[NOTIF_MAX_ARGS] ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \ ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \ ARG_CASE(ARG_CS_SV, "item_wepname", W_Name(f1)) \ + ARG_CASE(ARG_CS_SV, "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buff_Color(f1)), Buff_PrettyName(f1))) \ ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \ ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \ ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \ @@@ -1489,6 -1532,7 +1532,7 @@@ void RegisterNotifications_First( #endif printf("Beginning notification initialization on %s%s program...\n", dedi, PROGNAME); + #undef dedi // maybe do another implementation of this with checksums? for now, we don't need versioning /*if(autocvar_notification_version != NOTIF_VERSION) diff --combined qcsrc/common/turrets/sv_turrets.qc index 21ebc96fd,000000000..e979c4802 mode 100644,000000..100644 --- a/qcsrc/common/turrets/sv_turrets.qc +++ b/qcsrc/common/turrets/sv_turrets.qc @@@ -1,1396 -1,0 +1,1396 @@@ +// ========================= +// SVQC Turret Properties +// ========================= + + +// Generic aiming +vector turret_aim_generic() +{ + + vector pre_pos, prep; + float distance, impact_time = 0, i, mintime; + + turret_tag_fire_update(); + + if(self.aim_flags & TFL_AIM_SIMPLE) + return real_origin(self.enemy); + + mintime = max(self.attack_finished_single - time,0) + sys_frametime; + + // Baseline + pre_pos = real_origin(self.enemy); + + // Lead? + if (self.aim_flags & TFL_AIM_LEAD) + { + if (self.aim_flags & TFL_AIM_SHOTTIMECOMPENSATE) // Need to conpensate for shot traveltime + { + prep = pre_pos; + + distance = vlen(prep - self.tur_shotorg); + impact_time = distance / self.shot_speed; + + prep = pre_pos + (self.enemy.velocity * (impact_time + mintime)); + + if(self.aim_flags & TFL_AIM_ZPREDICT) + if(!(self.enemy.flags & FL_ONGROUND)) + if(self.enemy.movetype == MOVETYPE_WALK || self.enemy.movetype == MOVETYPE_TOSS || self.enemy.movetype == MOVETYPE_BOUNCE) + { + float vz; + prep_z = pre_pos_z; + vz = self.enemy.velocity_z; + for(i = 0; i < impact_time; i += sys_frametime) + { + vz = vz - (autocvar_sv_gravity * sys_frametime); + prep_z = prep_z + vz * sys_frametime; + } + } + pre_pos = prep; + } + else + pre_pos = pre_pos + self.enemy.velocity * mintime; + } + + if(self.aim_flags & TFL_AIM_SPLASH) + { + //tracebox(pre_pos + '0 0 32',self.enemy.mins,self.enemy.maxs,pre_pos -'0 0 64',MOVE_WORLDONLY,self.enemy); + traceline(pre_pos + '0 0 32',pre_pos -'0 0 64',MOVE_WORLDONLY,self.enemy); + if(trace_fraction != 1.0) + pre_pos = trace_endpos; + } + + return pre_pos; +} + +float turret_targetscore_support(entity _turret,entity _target) +{ + float score; // Total score + float s_score = 0, d_score; + + if (_turret.enemy == _target) s_score = 1; + + d_score = min(_turret.target_range_optimal,tvt_dist) / max(_turret.target_range_optimal,tvt_dist); + + score = (d_score * _turret.target_select_rangebias) + + (s_score * _turret.target_select_samebias); + + return score; +} + +/* +* Generic bias aware score system. +*/ +float turret_targetscore_generic(entity _turret, entity _target) +{ + float d_dist; // Defendmode Distance + float score; // Total score + float d_score; // Distance score + float a_score; // Angular score + float m_score = 0; // missile score + float p_score = 0; // player score + float ikr; // ideal kill range + + if (_turret.tur_defend) + { + d_dist = vlen(real_origin(_target) - _turret.tur_defend.origin); + ikr = vlen(_turret.origin - _turret.tur_defend.origin); + d_score = 1 - d_dist / _turret.target_range; + } + else + { + // Make a normlized value base on the targets distance from our optimal killzone + ikr = _turret.target_range_optimal; + d_score = min(ikr, tvt_dist) / max(ikr, tvt_dist); + } + + a_score = 1 - tvt_thadf / _turret.aim_maxrotate; + + if ((_turret.target_select_missilebias > 0) && (_target.flags & FL_PROJECTILE)) + m_score = 1; + + if ((_turret.target_select_playerbias > 0) && IS_CLIENT(_target)) + p_score = 1; + + d_score = max(d_score, 0); + a_score = max(a_score, 0); + m_score = max(m_score, 0); + p_score = max(p_score, 0); + + score = (d_score * _turret.target_select_rangebias) + + (a_score * _turret.target_select_anglebias) + + (m_score * _turret.target_select_missilebias) + + (p_score * _turret.target_select_playerbias); + + if(_turret.target_range < vlen(_turret.tur_shotorg - real_origin(_target))) + { + //dprint("Wtf?\n"); + score *= 0.001; + } + +#ifdef TURRET_DEBUG + string sd,sa,sm,sp,ss; + string sdt,sat,smt,spt; + + sd = ftos(d_score); + d_score *= _turret.target_select_rangebias; + sdt = ftos(d_score); + + //sv = ftos(v_score); + //v_score *= _turret.target_select_samebias; + //svt = ftos(v_score); + + sa = ftos(a_score); + a_score *= _turret.target_select_anglebias; + sat = ftos(a_score); + + sm = ftos(m_score); + m_score *= _turret.target_select_missilebias; + smt = ftos(m_score); + + sp = ftos(p_score); + p_score *= _turret.target_select_playerbias; + spt = ftos(p_score); + + + ss = ftos(score); + bprint("^3Target scores^7 \[ ",_turret.netname, " \] ^3for^7 \[ ", _target.netname," \]\n"); + bprint("^5Range:\[ ",sd, " \]^2+bias:\[ ",sdt," \]\n"); + bprint("^5Angle:\[ ",sa, " \]^2+bias:\[ ",sat," \]\n"); + bprint("^5Missile:\[ ",sm," \]^2+bias:\[ ",smt," \]\n"); + bprint("^5Player:\[ ",sp, " \]^2+bias:\[ ",spt," \]\n"); + bprint("^3Total (w/bias):\[^1",ss,"\]\n"); + +#endif + + return score; +} + +// Generic damage handling +void() turret_respawn; +void turret_hide() +{ + self.effects |= EF_NODRAW; + self.nextthink = time + self.respawntime - 0.2; + self.think = turret_respawn; +} + +void turret_die() +{ + self.deadflag = DEAD_DEAD; + self.tur_head.deadflag = self.deadflag; + +// Unsolidify and hide real parts + self.solid = SOLID_NOT; + self.tur_head.solid = self.solid; + + self.event_damage = func_null; + self.takedamage = DAMAGE_NO; + + self.health = 0; + +// Go boom + //RadiusDamage (self,self, min(self.ammo,50),min(self.ammo,50) * 0.25,250,world,min(self.ammo,50)*5,DEATH_TURRET,world); + + if(self.damage_flags & TFL_DMG_DEATH_NORESPAWN) + { + TUR_ACTION(self.turretid, TR_DEATH); + + remove(self.tur_head); + remove(self); + } + else + { + // Setup respawn + self.SendFlags |= TNSF_STATUS; + self.nextthink = time + 0.2; + self.think = turret_hide; + + TUR_ACTION(self.turretid, TR_DEATH); + } +} + +void turret_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) +{ + // Enougth allready! + if(self.deadflag == DEAD_DEAD) + return; + + // Inactive turrets take no damage. (hm..) + if(!self.active) + return; + + if (teamplay) + if (self.team == attacker.team) + { + // This does not happen anymore. Re-enable if you fix that. + if(IS_REAL_CLIENT(attacker)) + sprint(attacker, "\{1}Turret tells you: I'm on your team!\n"); + + if(autocvar_g_friendlyfire) + damage = damage * autocvar_g_friendlyfire; + else + return; + } + + self.health -= damage; + + // thorw head slightly off aim when hit? + if (self.damage_flags & TFL_DMG_HEADSHAKE) + { + self.tur_head.angles_x = self.tur_head.angles_x + (-0.5 + random()) * damage; + self.tur_head.angles_y = self.tur_head.angles_y + (-0.5 + random()) * damage; + + self.SendFlags |= TNSF_ANG; + } + + if (self.turret_flags & TUR_FLAG_MOVE) + self.velocity = self.velocity + vforce; + + if (self.health <= 0) + { + self.event_damage = func_null; + self.tur_head.event_damage = func_null; + self.takedamage = DAMAGE_NO; + self.nextthink = time; + self.think = turret_die; + } + + self.SendFlags |= TNSF_STATUS; +} + +void() turret_think; +void turret_respawn() +{ + // Make sure all parts belong to the same team since + // this function doubles as "teamchange" function. + self.tur_head.team = self.team; + self.effects &= ~EF_NODRAW; + self.deadflag = DEAD_NO; + self.effects = EF_LOWPRECISION; + self.solid = SOLID_BBOX; + self.takedamage = DAMAGE_AIM; + self.event_damage = turret_damage; + self.avelocity = '0 0 0'; + self.tur_head.avelocity = self.avelocity; + self.tur_head.angles = self.idle_aim; + self.health = self.max_health; + self.enemy = world; + self.volly_counter = self.shot_volly; + self.ammo = self.ammo_max; + + self.nextthink = time + self.ticrate; + self.think = turret_think; + + self.SendFlags = TNSF_FULL_UPDATE; + + TUR_ACTION(self.turretid, TR_SETUP); +} + + +// Main functions +#define cvar_base "g_turrets_unit_" +.float clientframe; +void turrets_setframe(float _frame, float client_only) +{ + if((client_only ? self.clientframe : self.frame ) != _frame) + { + self.SendFlags |= TNSF_ANIM; + self.anim_start_time = time; + } + + if(client_only) + self.clientframe = _frame; + else + self.frame = _frame; + +} + +float turret_send(entity to, float sf) +{ + + WriteByte(MSG_ENTITY, ENT_CLIENT_TURRET); + WriteByte(MSG_ENTITY, sf); + if(sf & TNSF_SETUP) + { + WriteByte(MSG_ENTITY, self.turretid); + + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteAngle(MSG_ENTITY, self.angles_x); + WriteAngle(MSG_ENTITY, self.angles_y); + } + + if(sf & TNSF_ANG) + { + WriteShort(MSG_ENTITY, rint(self.tur_head.angles_x)); + WriteShort(MSG_ENTITY, rint(self.tur_head.angles_y)); + } + + if(sf & TNSF_AVEL) + { + WriteShort(MSG_ENTITY, rint(self.tur_head.avelocity_x)); + WriteShort(MSG_ENTITY, rint(self.tur_head.avelocity_y)); + } + + if(sf & TNSF_MOVE) + { + WriteShort(MSG_ENTITY, rint(self.origin_x)); + WriteShort(MSG_ENTITY, rint(self.origin_y)); + WriteShort(MSG_ENTITY, rint(self.origin_z)); + + WriteShort(MSG_ENTITY, rint(self.velocity_x)); + WriteShort(MSG_ENTITY, rint(self.velocity_y)); + WriteShort(MSG_ENTITY, rint(self.velocity_z)); + + WriteShort(MSG_ENTITY, rint(self.angles_y)); + } + + if(sf & TNSF_ANIM) + { + WriteCoord(MSG_ENTITY, self.anim_start_time); + WriteByte(MSG_ENTITY, self.frame); + } + + if(sf & TNSF_STATUS) + { + WriteByte(MSG_ENTITY, self.team); + + if(self.health <= 0) + WriteByte(MSG_ENTITY, 0); + else + WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255)); + } + + return TRUE; +} + +void load_unit_settings(entity ent, string unitname, float is_reload) +{ + string sbase; + + if (ent == world) + return; + + if(!ent.turret_scale_damage) ent.turret_scale_damage = 1; + if(!ent.turret_scale_range) ent.turret_scale_range = 1; + if(!ent.turret_scale_refire) ent.turret_scale_refire = 1; + if(!ent.turret_scale_ammo) ent.turret_scale_ammo = 1; + if(!ent.turret_scale_aim) ent.turret_scale_aim = 1; + if(!ent.turret_scale_health) ent.turret_scale_health = 1; + if(!ent.turret_scale_respawn) ent.turret_scale_respawn = 1; + + sbase = strcat(cvar_base,unitname); + if (is_reload) + { + ent.enemy = world; + ent.tur_head.avelocity = '0 0 0'; + + ent.tur_head.angles = '0 0 0'; + } + + ent.health = cvar(strcat(sbase,"_health")) * ent.turret_scale_health; + ent.respawntime = cvar(strcat(sbase,"_respawntime")) * ent.turret_scale_respawn; + + ent.shot_dmg = cvar(strcat(sbase,"_shot_dmg")) * ent.turret_scale_damage; + ent.shot_refire = cvar(strcat(sbase,"_shot_refire")) * ent.turret_scale_refire; + ent.shot_radius = cvar(strcat(sbase,"_shot_radius")) * ent.turret_scale_damage; + ent.shot_speed = cvar(strcat(sbase,"_shot_speed")); + ent.shot_spread = cvar(strcat(sbase,"_shot_spread")); + ent.shot_force = cvar(strcat(sbase,"_shot_force")) * ent.turret_scale_damage; + ent.shot_volly = cvar(strcat(sbase,"_shot_volly")); + ent.shot_volly_refire = cvar(strcat(sbase,"_shot_volly_refire")) * ent.turret_scale_refire; + + ent.target_range = cvar(strcat(sbase,"_target_range")) * ent.turret_scale_range; + ent.target_range_min = cvar(strcat(sbase,"_target_range_min")) * ent.turret_scale_range; + ent.target_range_optimal = cvar(strcat(sbase,"_target_range_optimal")) * ent.turret_scale_range; + //ent.target_range_fire = cvar(strcat(sbase,"_target_range_fire")) * ent.turret_scale_range; + + ent.target_select_rangebias = cvar(strcat(sbase,"_target_select_rangebias")); + ent.target_select_samebias = cvar(strcat(sbase,"_target_select_samebias")); + ent.target_select_anglebias = cvar(strcat(sbase,"_target_select_anglebias")); + ent.target_select_playerbias = cvar(strcat(sbase,"_target_select_playerbias")); + //ent.target_select_fov = cvar(cvar_gets(sbase,"_target_select_fov")); + + ent.ammo_max = cvar(strcat(sbase,"_ammo_max")) * ent.turret_scale_ammo; + ent.ammo_recharge = cvar(strcat(sbase,"_ammo_recharge")) * ent.turret_scale_ammo; + + ent.aim_firetolerance_dist = cvar(strcat(sbase,"_aim_firetolerance_dist")); + ent.aim_speed = cvar(strcat(sbase,"_aim_speed")) * ent.turret_scale_aim; + ent.aim_maxrotate = cvar(strcat(sbase,"_aim_maxrot")); + ent.aim_maxpitch = cvar(strcat(sbase,"_aim_maxpitch")); + + ent.track_type = cvar(strcat(sbase,"_track_type")); + ent.track_accel_pitch = cvar(strcat(sbase,"_track_accel_pitch")); + ent.track_accel_rotate = cvar(strcat(sbase,"_track_accel_rot")); + ent.track_blendrate = cvar(strcat(sbase,"_track_blendrate")); + + if(is_reload) + TUR_ACTION(self.turretid, TR_SETUP); +} + +void turret_projectile_explode() +{ + + self.takedamage = DAMAGE_NO; + self.event_damage = func_null; +#ifdef TURRET_DEBUG + float d; + d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world); + self.owner.tur_debug_dmg_t_h = self.owner.tur_debug_dmg_t_h + d; + self.owner.tur_debug_dmg_t_f = self.owner.tur_debug_dmg_t_f + self.owner.shot_dmg; +#else + RadiusDamage (self, self.realowner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world); +#endif + remove(self); +} + +void turret_projectile_touch() +{ + PROJECTILE_TOUCH; + turret_projectile_explode(); +} + +void turret_projectile_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce) +{ + self.velocity += vforce; + self.health -= damage; + //self.realowner = attacker; // Dont change realowner, it does not make much sense for turrets + if(self.health <= 0) + W_PrepareExplosionByDamage(self.owner, turret_projectile_explode); +} + +entity turret_projectile(string _snd, float _size, float _health, float _death, float _proj_type, float _cull, float _cli_anim) +{ + entity proj; + + sound (self, CH_WEAPON_A, _snd, VOL_BASE, ATTEN_NORM); + proj = spawn (); + setorigin(proj, self.tur_shotorg); + setsize(proj, '-0.5 -0.5 -0.5' * _size, '0.5 0.5 0.5' * _size); + proj.owner = self; + proj.realowner = self; + proj.bot_dodge = TRUE; + proj.bot_dodgerating = self.shot_dmg; + proj.think = turret_projectile_explode; + proj.touch = turret_projectile_touch; + proj.nextthink = time + 9; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.velocity = normalize(self.tur_shotdir_updated + randomvec() * self.shot_spread) * self.shot_speed; + proj.flags = FL_PROJECTILE; + proj.enemy = self.enemy; + proj.totalfrags = _death; + PROJECTILE_MAKETRIGGER(proj); + if(_health) + { + proj.health = _health; + proj.takedamage = DAMAGE_YES; + proj.event_damage = turret_projectile_damage; + } + else + proj.flags |= FL_NOTARGET; + + CSQCProjectile(proj, _cli_anim, _proj_type, _cull); + + return proj; +} + +/** +** updates enemy distances, predicted impact point/time +** and updated aim<->predict impact distance. +**/ +void turret_do_updates(entity t_turret) +{ + vector enemy_pos; + entity oldself; + + oldself = self; + self = t_turret; + + enemy_pos = real_origin(self.enemy); + + turret_tag_fire_update(); + + self.tur_shotdir_updated = v_forward; + self.tur_dist_enemy = vlen(self.tur_shotorg - enemy_pos); + self.tur_dist_aimpos = vlen(self.tur_shotorg - self.tur_aimpos); + + /*if((self.firecheck_flags & TFL_FIRECHECK_VERIFIED) && (self.enemy)) + { + oldpos = self.enemy.origin; + setorigin(self.enemy, self.tur_aimpos); + tracebox(self.tur_shotorg, '-1 -1 -1', '1 1 1', self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos), MOVE_NORMAL,self); + setorigin(self.enemy, oldpos); + + if(trace_ent == self.enemy) + self.tur_dist_impact_to_aimpos = 0; + else + self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos); + } + else*/ + tracebox(self.tur_shotorg, '-1 -1 -1','1 1 1', self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos), MOVE_NORMAL,self); + + self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos) - (vlen(self.enemy.maxs - self.enemy.mins) * 0.5); + self.tur_impactent = trace_ent; + self.tur_impacttime = vlen(self.tur_shotorg - trace_endpos) / self.shot_speed; + + self = oldself; +} + +/** +** Handles head rotation according to +** the units .track_type and .track_flags +**/ +.float turret_framecounter; +void turret_track() +{ + vector target_angle; // This is where we want to aim + vector move_angle; // This is where we can aim + float f_tmp; + vector v1, v2; + v1 = self.tur_head.angles; + v2 = self.tur_head.avelocity; + + if (self.track_flags == TFL_TRACK_NO) + return; + + if(!self.active) + target_angle = self.idle_aim - ('1 0 0' * self.aim_maxpitch); + else if (self.enemy == world) + { + if(time > self.lip) + target_angle = self.idle_aim + self.angles; + else + target_angle = vectoangles(normalize(self.tur_aimpos - self.tur_shotorg)); + } + else + { + target_angle = vectoangles(normalize(self.tur_aimpos - self.tur_shotorg)); + } + + self.tur_head.angles_x = anglemods(self.tur_head.angles_x); + self.tur_head.angles_y = anglemods(self.tur_head.angles_y); + + // Find the diffrence between where we currently aim and where we want to aim + //move_angle = target_angle - (self.angles + self.tur_head.angles); + //move_angle = shortangle_vxy(move_angle,(self.angles + self.tur_head.angles)); + + move_angle = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(self.angles), AnglesTransform_FromAngles(target_angle))) - self.tur_head.angles; + move_angle = shortangle_vxy(move_angle, self.tur_head.angles); + + switch(self.track_type) + { + case TFL_TRACKTYPE_STEPMOTOR: + f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic + if (self.track_flags & TFL_TRACK_PITCH) + { + self.tur_head.angles_x += bound(-f_tmp,move_angle_x, f_tmp); + if(self.tur_head.angles_x > self.aim_maxpitch) + self.tur_head.angles_x = self.aim_maxpitch; + + if(self.tur_head.angles_x < -self.aim_maxpitch) + self.tur_head.angles_x = self.aim_maxpitch; + } + + if (self.track_flags & TFL_TRACK_ROTATE) + { + self.tur_head.angles_y += bound(-f_tmp, move_angle_y, f_tmp); + if(self.tur_head.angles_y > self.aim_maxrotate) + self.tur_head.angles_y = self.aim_maxrotate; + + if(self.tur_head.angles_y < -self.aim_maxrotate) + self.tur_head.angles_y = self.aim_maxrotate; + } + + // CSQC + self.SendFlags |= TNSF_ANG; + + return; + + case TFL_TRACKTYPE_FLUIDINERTIA: + f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic + move_angle_x = bound(-self.aim_speed, move_angle_x * self.track_accel_pitch * f_tmp, self.aim_speed); + move_angle_y = bound(-self.aim_speed, move_angle_y * self.track_accel_rotate * f_tmp, self.aim_speed); + move_angle = (self.tur_head.avelocity * self.track_blendrate) + (move_angle * (1 - self.track_blendrate)); + break; + + case TFL_TRACKTYPE_FLUIDPRECISE: + + move_angle_y = bound(-self.aim_speed, move_angle_y, self.aim_speed); + move_angle_x = bound(-self.aim_speed, move_angle_x, self.aim_speed); + + break; + } + + // pitch + if (self.track_flags & TFL_TRACK_PITCH) + { + self.tur_head.avelocity_x = move_angle_x; + if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) > self.aim_maxpitch) + { + self.tur_head.avelocity_x = 0; + self.tur_head.angles_x = self.aim_maxpitch; + + self.SendFlags |= TNSF_ANG; + } + + if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) < -self.aim_maxpitch) + { + self.tur_head.avelocity_x = 0; + self.tur_head.angles_x = -self.aim_maxpitch; + + self.SendFlags |= TNSF_ANG; + } + } + + // rot + if (self.track_flags & TFL_TRACK_ROTATE) + { + self.tur_head.avelocity_y = move_angle_y; + + if((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate) > self.aim_maxrotate) + { + self.tur_head.avelocity_y = 0; + self.tur_head.angles_y = self.aim_maxrotate; + + self.SendFlags |= TNSF_ANG; + } + + if((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate) < -self.aim_maxrotate) + { + self.tur_head.avelocity_y = 0; + self.tur_head.angles_y = -self.aim_maxrotate; + + self.SendFlags |= TNSF_ANG; + } + } + + self.SendFlags |= TNSF_AVEL; + + // Force a angle update every 10'th frame + self.turret_framecounter += 1; + if(self.turret_framecounter >= 10) + { + self.SendFlags |= TNSF_ANG; + self.turret_framecounter = 0; + } +} + +/* + + TFL_TARGETSELECT_NO + + TFL_TARGETSELECT_LOS + + TFL_TARGETSELECT_PLAYERS + + TFL_TARGETSELECT_MISSILES + - TFL_TARGETSELECT_TRIGGERTARGET + + TFL_TARGETSELECT_ANGLELIMITS + + TFL_TARGETSELECT_RANGELIMITS + + TFL_TARGETSELECT_TEAMCHECK + - TFL_TARGETSELECT_NOBUILTIN + + TFL_TARGETSELECT_OWNTEAM +*/ + +/** +** Evaluate a entity for target valitity based on validate_flags +** NOTE: the caller must check takedamage before calling this, to inline this check. +**/ +float turret_validate_target(entity e_turret, entity e_target, float validate_flags) +{ + vector v_tmp; + + //if(!validate_flags & TFL_TARGETSELECT_NOBUILTIN) + // return -0.5; + + if(e_target.owner == e_turret) + return -0.5; + + if(!checkpvs(e_target.origin, e_turret)) + return -1; + + if(!e_target) + return -2; + + if(g_onslaught) + if (substring(e_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job! + return - 3; + + if (validate_flags & TFL_TARGETSELECT_NO) + return -4; + + // If only this was used more.. + if (e_target.flags & FL_NOTARGET) + return -5; + + // Cant touch this + if(e_target.vehicle_flags & VHF_ISVEHICLE) + { + if (e_target.vehicle_health <= 0) + return -6; + } + else if (e_target.health <= 0) + return -6; - else if(e_target.freezetag_frozen > 0) ++ else if(e_target.frozen > 0) + return -6; + + // player + if (IS_CLIENT(e_target)) + { + if(!(validate_flags & TFL_TARGETSELECT_PLAYERS)) + return -7; + + if (e_target.deadflag != DEAD_NO) + return -8; + } + + // enemy turrets + if(validate_flags & TFL_TARGETSELECT_NOTURRETS) + if(e_target.owner.tur_head == e_target) + if(e_target.team != e_turret.team) // Dont break support units. + return -9; + + // Missile + if (e_target.flags & FL_PROJECTILE) + if(!(validate_flags & TFL_TARGETSELECT_MISSILES)) + return -10; + + if (validate_flags & TFL_TARGETSELECT_MISSILESONLY) + if(!(e_target.flags & FL_PROJECTILE)) + return -10.5; + + // Team check + if (validate_flags & TFL_TARGETSELECT_TEAMCHECK) + { + if (validate_flags & TFL_TARGETSELECT_OWNTEAM) + { + if (e_target.team != e_turret.team) + return -11; + + if (e_turret.team != e_target.owner.team) + return -12; + } + else + { + if (e_target.team == e_turret.team) + return -13; + + if (e_turret.team == e_target.owner.team) + return -14; + } + } + + // Range limits? + tvt_dist = vlen(e_turret.origin - real_origin(e_target)); + if (validate_flags & TFL_TARGETSELECT_RANGELIMITS) + { + if (tvt_dist < e_turret.target_range_min) + return -15; + + if (tvt_dist > e_turret.target_range) + return -16; + } + + // Can we even aim this thing? + tvt_thadv = angleofs3(e_turret.tur_head.origin, e_turret.angles + e_turret.tur_head.angles, e_target); + tvt_tadv = shortangle_vxy(angleofs(e_turret, e_target), e_turret.angles); + tvt_thadf = vlen(tvt_thadv); + tvt_tadf = vlen(tvt_tadv); + + /* + if(validate_flags & TFL_TARGETSELECT_FOV) + { + if(e_turret.target_select_fov < tvt_thadf) + return -21; + } + */ + + if (validate_flags & TFL_TARGETSELECT_ANGLELIMITS) + { + if (fabs(tvt_tadv_x) > e_turret.aim_maxpitch) + return -17; + + if (fabs(tvt_tadv_y) > e_turret.aim_maxrotate) + return -18; + } + + // Line of sight? + if (validate_flags & TFL_TARGETSELECT_LOS) + { + v_tmp = real_origin(e_target) + ((e_target.mins + e_target.maxs) * 0.5); + + traceline(e_turret.origin + '0 0 16', v_tmp, 0, e_turret); + + if (e_turret.aim_firetolerance_dist < vlen(v_tmp - trace_endpos)) + return -19; + } + + if (e_target.classname == "grapplinghook") + return -20; + + /* + if (e_target.classname == "func_button") + return -21; + */ + +#ifdef TURRET_DEBUG_TARGETSELECT + dprint("Target:",e_target.netname," is a valid target for ",e_turret.netname,"\n"); +#endif + + return 1; +} + +entity turret_select_target() +{ + entity e; // target looper entity + float score; // target looper entity score + entity e_enemy; // currently best scoreing target + float m_score; // currently best scoreing target's score + + m_score = 0; + if(self.enemy && self.enemy.takedamage && turret_validate_target(self,self.enemy,self.target_validate_flags) > 0) + { + e_enemy = self.enemy; + m_score = self.turret_score_target(self,e_enemy) * self.target_select_samebias; + } + else + e_enemy = self.enemy = world; + + e = findradius(self.origin, self.target_range); + + // Nothing to aim at? + if (!e) + return world; + + while (e) + { + if(e.takedamage) + { + float f = turret_validate_target(self, e, self.target_select_flags); + //dprint("F is: ", ftos(f), "\n"); + if ( f > 0) + { + score = self.turret_score_target(self,e); + if ((score > m_score) && (score > 0)) + { + e_enemy = e; + m_score = score; + } + } + } + e = e.chain; + } + + return e_enemy; +} + + +/* + + = implemented + - = not implemented + + + TFL_FIRECHECK_NO + + TFL_FIRECHECK_WORLD + + TFL_FIRECHECK_DEAD + + TFL_FIRECHECK_DISTANCES + - TFL_FIRECHECK_LOS + + TFL_FIRECHECK_AIMDIST + + TFL_FIRECHECK_REALDIST + - TFL_FIRECHECK_ANGLEDIST + - TFL_FIRECHECK_TEAMCECK + + TFL_FIRECHECK_AFF + + TFL_FIRECHECK_AMMO_OWN + + TFL_FIRECHECK_AMMO_OTHER + + TFL_FIRECHECK_REFIRE +*/ + +/** +** Preforms pre-fire checks based on the uints firecheck_flags +**/ +float turret_firecheck() +{ + // This one just dont care =) + if (self.firecheck_flags & TFL_FIRECHECK_NO) + return 1; + + if (self.enemy == world) + return 0; + + // Ready? + if (self.firecheck_flags & TFL_FIRECHECK_REFIRE) + if (self.attack_finished_single > time) return 0; + + // Special case: volly fire turret that has to fire a full volly if a shot was fired. + if (self.shoot_flags & TFL_SHOOT_VOLLYALWAYS) + if (self.volly_counter != self.shot_volly) + if(self.ammo >= self.shot_dmg) + return 1; + + // Lack of zombies makes shooting dead things unnecessary :P + if (self.firecheck_flags & TFL_FIRECHECK_DEAD) + if (self.enemy.deadflag != DEAD_NO) + return 0; + + // Own ammo? + if (self.firecheck_flags & TFL_FIRECHECK_AMMO_OWN) + if (self.ammo < self.shot_dmg) + return 0; + + // Other's ammo? (support-supply units) + if (self.firecheck_flags & TFL_FIRECHECK_AMMO_OTHER) + if (self.enemy.ammo >= self.enemy.ammo_max) + return 0; + + // Target of opertunity? + if(turret_validate_target(self, self.tur_impactent, self.target_validate_flags) > 0) + { + self.enemy = self.tur_impactent; + return 1; + } + + if (self.firecheck_flags & TFL_FIRECHECK_DISTANCES) + { + // To close? + if (self.tur_dist_aimpos < self.target_range_min) + if(turret_validate_target(self, self.tur_impactent, self.target_validate_flags) > 0) + return 1; // Target of opertunity? + else + return 0; + } + + // Try to avoid FF? + if (self.firecheck_flags & TFL_FIRECHECK_AFF) + if (self.tur_impactent.team == self.team) + return 0; + + // aim<->predicted impact + if (self.firecheck_flags & TFL_FIRECHECK_AIMDIST) + if (self.tur_dist_impact_to_aimpos > self.aim_firetolerance_dist) + return 0; + + // Volly status + if (self.shot_volly > 1) + if (self.volly_counter == self.shot_volly) + if (self.ammo < (self.shot_dmg * self.shot_volly)) + return 0; + + /*if(self.firecheck_flags & TFL_FIRECHECK_VERIFIED) + if(self.tur_impactent != self.enemy) + return 0;*/ + + return 1; +} + +void turret_fire() +{ + if (autocvar_g_turrets_nofire != 0) + return; + + TUR_ACTION(self.turretid, TR_ATTACK); + + self.attack_finished_single = time + self.shot_refire; + self.ammo -= self.shot_dmg; + self.volly_counter = self.volly_counter - 1; + + if (self.volly_counter <= 0) + { + self.volly_counter = self.shot_volly; + + if (self.shoot_flags & TFL_SHOOT_CLEARTARGET) + self.enemy = world; + + if (self.shot_volly > 1) + self.attack_finished_single = time + self.shot_volly_refire; + } + +#ifdef TURRET_DEBUG + if (self.enemy) paint_target3(self.tur_aimpos, 64, self.tur_debug_rvec, self.tur_impacttime + 0.25); +#endif +} + +void turret_think() +{ + entity e; + + self.nextthink = time + self.ticrate; + + // ONS uses somewhat backwards linking. + if (teamplay) + { + if (g_onslaught) + if (self.target) + { + e = find(world, targetname,self.target); + if (e != world) + self.team = e.team; + } + + if (self.team != self.tur_head.team) + turret_respawn(); + } + +#ifdef TURRET_DEBUG + if (self.tur_debug_tmr1 < time) + { + if (self.enemy) paint_target (self.enemy,128,self.tur_debug_rvec,0.9); + paint_target(self,256,self.tur_debug_rvec,0.9); + self.tur_debug_tmr1 = time + 1; + } +#endif + + // Handle ammo + if (!(self.spawnflags & TSF_NO_AMMO_REGEN)) + if (self.ammo < self.ammo_max) + self.ammo = min(self.ammo + self.ammo_recharge, self.ammo_max); + + // Inactive turrets needs to run the think loop, + // So they can handle animation and wake up if need be. + if(!self.active) + { + turret_track(); + return; + } + + // This is typicaly used for zaping every target in range + // turret_fusionreactor uses this to recharge friendlys. + if (self.shoot_flags & TFL_SHOOT_HITALLVALID) + { + // Do a self.turret_fire for every valid target. + e = findradius(self.origin,self.target_range); + while (e) + { + if(e.takedamage) + { + if (turret_validate_target(self,e,self.target_validate_flags)) + { + self.enemy = e; + + turret_do_updates(self); + + if (self.turret_firecheckfunc()) + turret_fire(); + } + } + + e = e.chain; + } + self.enemy = world; + } + else if(self.shoot_flags & TFL_SHOOT_CUSTOM) + { + // This one is doing something.. oddball. assume its handles what needs to be handled. + + // Predict? + if(!(self.aim_flags & TFL_AIM_NO)) + self.tur_aimpos = turret_aim_generic(); + + // Turn & pitch? + if(!(self.track_flags & TFL_TRACK_NO)) + turret_track(); + + turret_do_updates(self); + + // Fire? + if (self.turret_firecheckfunc()) + turret_fire(); + } + else + { + // Special case for volly always. if it fired once it must compleate the volly. + if(self.shoot_flags & TFL_SHOOT_VOLLYALWAYS) + if(self.volly_counter != self.shot_volly) + { + // Predict or whatnot + if(!(self.aim_flags & TFL_AIM_NO)) + self.tur_aimpos = turret_aim_generic(); + + // Turn & pitch + if(!(self.track_flags & TFL_TRACK_NO)) + turret_track(); + + turret_do_updates(self); + + // Fire! + if (self.turret_firecheckfunc() != 0) + turret_fire(); + + TUR_ACTION(self.turretid, TR_THINK); + + return; + } + + // Check if we have a vailid enemy, and try to find one if we dont. + + // g_turrets_targetscan_maxdelay forces a target re-scan at least this often + float do_target_scan = 0; + if((self.target_select_time + autocvar_g_turrets_targetscan_maxdelay) < time) + do_target_scan = 1; + + // Old target (if any) invalid? + if(self.target_validate_time < time) + if (turret_validate_target(self, self.enemy, self.target_validate_flags) <= 0) + { + self.enemy = world; + self.target_validate_time = time + 0.5; + do_target_scan = 1; + } + + // But never more often then g_turrets_targetscan_mindelay! + if (self.target_select_time + autocvar_g_turrets_targetscan_mindelay > time) + do_target_scan = 0; + + if(do_target_scan) + { + self.enemy = turret_select_target(); + self.target_select_time = time; + } + + // No target, just go to idle, do any custom stuff and bail. + if (self.enemy == world) + { + // Turn & pitch + if(!(self.track_flags & TFL_TRACK_NO)) + turret_track(); + + TUR_ACTION(self.turretid, TR_THINK); + + // And bail. + return; + } + else + self.lip = time + autocvar_g_turrets_aimidle_delay; // Keep track of the last time we had a target. + + // Predict? + if(!(self.aim_flags & TFL_AIM_NO)) + self.tur_aimpos = turret_aim_generic(); + + // Turn & pitch? + if(!(self.track_flags & TFL_TRACK_NO)) + turret_track(); + + turret_do_updates(self); + + // Fire? + if (self.turret_firecheckfunc()) + turret_fire(); + } + + TUR_ACTION(self.turretid, TR_THINK); +} + +/* + When .used a turret switch team to activator.team. + If activator is world, the turret go inactive. +*/ +void turret_use() +{ + dprint("Turret ",self.netname, " used by ", activator.classname, "\n"); + + self.team = activator.team; + + if(self.team == 0) + self.active = ACTIVE_NOT; + else + self.active = ACTIVE_ACTIVE; + +} + +void turret_link() +{ + Net_LinkEntity(self, TRUE, 0, turret_send); + self.think = turret_think; + self.nextthink = time; + self.tur_head.effects = EF_NODRAW; +} + +void turrets_manager_think() +{ + self.nextthink = time + 1; + + entity e; + if (autocvar_g_turrets_reloadcvars == 1) + { + e = nextent(world); + while (e) + { + if (e.turret_flags & TUR_FLAG_ISTURRET) + { + load_unit_settings(e,e.cvar_basename,1); + TUR_ACTION(self.turretid, TR_THINK); + } + + e = nextent(e); + } + cvar_set("g_turrets_reloadcvars","0"); + } +} + +float turret_initialize(float tur_id) +{ + if(!autocvar_g_turrets) + return FALSE; + + entity e; + entity tur = get_turretinfo(tur_id); + if(tur.turretid == 0) + return FALSE; // invalid turret + + e = find(world, classname, "turret_manager"); + if(!e) + { + e = spawn(); + e.classname = "turret_manager"; + e.think = turrets_manager_think; + e.nextthink = time + 2; + } + + if(!(self.spawnflags & TSF_SUSPENDED)) + builtin_droptofloor(); + + self.cvar_basename = tur.cvar_basename; + load_unit_settings(self, self.cvar_basename, 0); + + if(!self.team || !teamplay) { self.team = MAX_SHOT_DISTANCE; } + if(!self.ticrate) { self.ticrate = ((self.turret_flags & TUR_FLAG_SUPPORT) ? 0.2 : 0.1); } + if(!self.health) { self.health = 1000; } + if(!self.shot_refire) { self.shot_refire = 1; } + if(!self.tur_shotorg) { self.tur_shotorg = '50 0 50'; } + if(!self.turret_flags) { self.turret_flags = TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER; } + if(!self.damage_flags) { self.damage_flags = TFL_DMG_YES | TFL_DMG_RETALIATE | TFL_DMG_AIMSHAKE; } + if(!self.aim_flags) { self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE; } + if(!self.track_type) { self.track_type = TFL_TRACKTYPE_STEPMOTOR; } + if(!self.track_flags) { self.track_flags = TFL_TRACK_PITCH | TFL_TRACK_ROTATE; } + if(!self.ammo_flags) { self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE; } + if(!self.target_select_flags) { self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_ANGLELIMITS; } + if(!self.firecheck_flags) { self.firecheck_flags = TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES | TFL_FIRECHECK_LOS + | TFL_FIRECHECK_AIMDIST | TFL_FIRECHECK_TEAMCHECK | TFL_FIRECHECK_AMMO_OWN | TFL_FIRECHECK_REFIRE; } + + if(self.track_type != TFL_TRACKTYPE_STEPMOTOR) + { + // Fluid / Ineria mode. Looks mutch nicer. + // Can reduce aim preformance alot, needs a bit diffrent aimspeed + + self.aim_speed = bound(0.1, ((!self.aim_speed) ? 180 : self.aim_speed), 1000); + + if(!self.track_accel_pitch) { self.track_accel_pitch = 0.5; } + if(!self.track_accel_rotate) { self.track_accel_rotate = 0.5; } + if(!self.track_blendrate) { self.track_blendrate = 0.35; } + } + + self.respawntime = max(-1, ((!self.respawntime) ? 60 : self.respawntime)); + self.shot_refire = bound(0.01, ((!self.shot_refire) ? 1 : self.shot_refire), 9999); + self.shot_dmg = max(1, ((!self.shot_dmg) ? self.shot_refire * 50 : self.shot_dmg)); + self.shot_radius = max(1, ((!self.shot_radius) ? self.shot_dmg * 0.5 : self.shot_radius)); + self.shot_speed = max(1, ((!self.shot_speed) ? 2500 : self.shot_speed)); + self.shot_spread = bound(0.0001, ((!self.shot_spread) ? 0.0125 : self.shot_spread), 500); + self.shot_force = bound(0.001, ((!self.shot_force) ? self.shot_dmg * 0.5 + self.shot_radius * 0.5 : self.shot_force), 5000); + self.shot_volly = bound(1, ((!self.shot_volly) ? 1 : self.shot_volly), floor(self.ammo_max / self.shot_dmg)); + self.shot_volly_refire = bound(self.shot_refire, ((!self.shot_volly_refire) ? self.shot_refire * self.shot_volly : self.shot_volly_refire), 60); + self.target_range = bound(0, ((!self.target_range) ? self.shot_speed * 0.5 : self.target_range), MAX_SHOT_DISTANCE); + self.target_range_min = bound(0, ((!self.target_range_min) ? self.shot_radius * 2 : self.target_range_min), MAX_SHOT_DISTANCE); + self.target_range_optimal = bound(0, ((!self.target_range_optimal) ? self.target_range * 0.5 : self.target_range_optimal), MAX_SHOT_DISTANCE); + self.aim_maxrotate = bound(0, ((!self.aim_maxrotate) ? 90 : self.aim_maxrotate), 360); + self.aim_maxpitch = bound(0, ((!self.aim_maxpitch) ? 20 : self.aim_maxpitch), 90); + self.aim_speed = bound(0.1, ((!self.aim_speed) ? 36 : self.aim_speed), 1000); + self.aim_firetolerance_dist = bound(0.1, ((!self.aim_firetolerance_dist) ? 5 + (self.shot_radius * 2) : self.aim_firetolerance_dist), MAX_SHOT_DISTANCE); + self.target_select_rangebias = bound(-10, ((!self.target_select_rangebias) ? 1 : self.target_select_rangebias), 10); + self.target_select_samebias = bound(-10, ((!self.target_select_samebias) ? 1 : self.target_select_samebias), 10); + self.target_select_anglebias = bound(-10, ((!self.target_select_anglebias) ? 1 : self.target_select_anglebias), 10); + self.target_select_missilebias = bound(-10, ((!self.target_select_missilebias) ? 1 : self.target_select_missilebias), 10); + self.target_select_playerbias = bound(-10, ((!self.target_select_playerbias) ? 1 : self.target_select_playerbias), 10); + self.ammo_max = max(self.shot_dmg, ((!self.ammo_max) ? self.shot_dmg * 10 : self.ammo_max)); + self.ammo_recharge = max(0, ((!self.ammo_recharge) ? self.shot_dmg * 0.5 : self.ammo_recharge)); + + self.turret_flags = TUR_FLAG_ISTURRET | (tur.spawnflags); + + if(self.turret_flags & TUR_FLAG_SPLASH) + self.aim_flags |= TFL_AIM_SPLASH; + + if(self.turret_flags & TUR_FLAG_MISSILE) + self.target_select_flags |= TFL_TARGETSELECT_MISSILES; + + if(self.turret_flags & TUR_FLAG_PLAYER) + self.target_select_flags |= TFL_TARGETSELECT_PLAYERS; + + if(self.spawnflags & TSL_NO_RESPAWN) + self.damage_flags |= TFL_DMG_DEATH_NORESPAWN; + + if (self.turret_flags & TUR_FLAG_SUPPORT) + self.turret_score_target = turret_targetscore_support; + else + self.turret_score_target = turret_targetscore_generic; + + ++turret_count; + + setmodel(self, tur.model); + setsize(self, tur.mins, tur.maxs); + + self.turretid = tur_id; + self.classname = "turret_main"; + self.active = ACTIVE_ACTIVE; + self.effects = EF_NODRAW; + self.netname = TUR_NAME(tur_id); + self.ticrate = bound(sys_frametime, self.ticrate, 60); + self.max_health = self.health; + self.target_validate_flags = self.target_select_flags; + self.ammo = self.ammo_max; + self.ammo_recharge *= self.ticrate; + self.solid = SOLID_BBOX; + self.takedamage = DAMAGE_AIM; + self.movetype = MOVETYPE_NOCLIP; + self.view_ofs = '0 0 0'; + self.turret_firecheckfunc = turret_firecheck; + self.event_damage = turret_damage; + self.use = turret_use; + self.bot_attack = TRUE; + self.nextthink = time + 1; + self.nextthink += turret_count * sys_frametime; + + self.tur_head = spawn(); + setmodel(self.tur_head, tur.head_model); + setsize(self.tur_head, '0 0 0', '0 0 0'); + setorigin(self.tur_head, '0 0 0'); + setattachment(self.tur_head, self, "tag_head"); + + self.tur_head.netname = self.tur_head.classname = "turret_head"; + self.tur_head.team = self.team; + self.tur_head.owner = self; + self.tur_head.takedamage = DAMAGE_NO; + self.tur_head.solid = SOLID_NOT; + self.tur_head.movetype = self.movetype; + + if(!self.tur_defend) + if(self.target != "") + { + self.tur_defend = find(world, targetname, self.target); + if (self.tur_defend == world) + { + self.target = ""; + dprint("Turret has invalid defendpoint!\n"); + } + } + + if (self.tur_defend) + self.idle_aim = self.tur_head.angles + angleofs(self.tur_head, self.tur_defend); + else + self.idle_aim = '0 0 0'; + +#ifdef TURRET_DEBUG + self.tur_debug_start = self.nextthink; + while (vlen(self.tur_debug_rvec) < 2) + self.tur_debug_rvec = randomvec() * 4; + + self.tur_debug_rvec_x = fabs(self.tur_debug_rvec_x); + self.tur_debug_rvec_y = fabs(self.tur_debug_rvec_y); + self.tur_debug_rvec_z = fabs(self.tur_debug_rvec_z); +#endif + + turret_link(); + turret_respawn(); + turret_tag_fire_update(); + + TUR_ACTION(tur_id, TR_SETUP); + + if(MUTATOR_CALLHOOK(TurretSpawn)) + return FALSE; + + return TRUE; +} diff --combined qcsrc/common/turrets/unit/plasma.qc index 0cd18fa91,000000000..6ffd63519 mode 100644,000000..100644 --- a/qcsrc/common/turrets/unit/plasma.qc +++ b/qcsrc/common/turrets/unit/plasma.qc @@@ -1,113 -1,0 +1,113 @@@ +#ifdef REGISTER_TURRET +REGISTER_TURRET( +/* TUR_##id */ PLASMA, +/* function */ t_plasma, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "plasma.md3", +/* netname */ "plasma", +/* fullname */ _("Plasma Cannon") +); +#else +#ifdef SVQC +void spawnfunc_turret_plasma() { if(!turret_initialize(TUR_PLASMA)) remove(self); } + +float t_plasma(float req) +{ + switch(req) + { + case TR_ATTACK: + { - if(g_minstagib) ++ if(g_instagib) + { + float flying; + flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last + + FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); + + pointparticles(particleeffectnum("nex_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + // teamcolor / hit beam effect + vector v; + string s; + v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); - s = strcat("TE_TEI_G3", Static_Team_ColorName_Upper(self.team)); ++ s = strcat("TE_TEI_G3", ((self.team) ? Static_Team_ColorName_Upper(self.team) : "")); + + WarpZone_TrailParticles(world, particleeffectnum(s), self.tur_shotorg, v); + + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; + } + else + { + entity missile = turret_projectile("weapons/hagar_fire.wav", 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); + missile.missile_flags = MIF_SPLASH; + + pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + if (self.tur_head.frame == 0) + self.tur_head.frame = 1; + } + + return TRUE; + } + case TR_THINK: + { + if (self.tur_head.frame != 0) + self.tur_head.frame = self.tur_head.frame + 1; + + if (self.tur_head.frame > 5) + self.tur_head.frame = 0; + + return TRUE; + } + case TR_DEATH: + { + return TRUE; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.firecheck_flags |= TFL_FIRECHECK_AFF; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; + + turret_do_updates(self); + + return TRUE; + } + case TR_PRECACHE: + { + precache_model ("models/turrets/base.md3"); + precache_model ("models/turrets/plasma.md3"); + return TRUE; + } + } + + return TRUE; +} + +#endif // SVQC +#ifdef CSQC +float t_plasma(float req) +{ + switch(req) + { + case TR_SETUP: + { + return TRUE; + } + case TR_PRECACHE: + { + precache_model ("models/turrets/base.md3"); + precache_model ("models/turrets/plasma.md3"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --combined qcsrc/common/turrets/unit/plasma_dual.qc index e1e2f1ad9,000000000..e2432dd0f mode 100644,000000..100644 --- a/qcsrc/common/turrets/unit/plasma_dual.qc +++ b/qcsrc/common/turrets/unit/plasma_dual.qc @@@ -1,111 -1,0 +1,111 @@@ +#ifdef REGISTER_TURRET +REGISTER_TURRET( +/* TUR_##id */ PLASMA_DUAL, +/* function */ t_plasma_dual, +/* spawnflags */ TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER, +/* mins,maxs */ '-32 -32 0', '32 32 64', +/* model */ "base.md3", +/* head_model */ "plasmad.md3", +/* netname */ "plasma_dual", +/* fullname */ _("Dual Plasma Cannon") +); +#else +#ifdef SVQC +void spawnfunc_turret_plasma_dual() { if(!turret_initialize(TUR_PLASMA_DUAL)) remove(self); } + +float t_plasma_dual(float req) +{ + switch(req) + { + case TR_ATTACK: + { - if(g_minstagib) ++ if(g_instagib) + { + float flying; + flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last + + FireRailgunBullet (self.tur_shotorg, self.tur_shotorg + self.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA); + + + pointparticles(particleeffectnum("nex_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + + // teamcolor / hit beam effect + vector v; + string s; + v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); - s = strcat("TE_TEI_G3", Static_Team_ColorName_Upper(self.team)); ++ s = strcat("TE_TEI_G3", ((self.team) ? Static_Team_ColorName_Upper(self.team) : "")); + + WarpZone_TrailParticles(world, particleeffectnum(s), self.tur_shotorg, v); + + self.tur_head.frame += 1; + } + else + { + entity missile = turret_projectile("weapons/hagar_fire.wav", 1, 0, DEATH_TURRET_PLASMA, PROJECTILE_ELECTRO_BEAM, TRUE, TRUE); + missile.missile_flags = MIF_SPLASH; + pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1); + self.tur_head.frame += 1; + } + + return TRUE; + } + case TR_THINK: + { + if ((self.tur_head.frame != 0) && (self.tur_head.frame != 3)) + self.tur_head.frame = self.tur_head.frame + 1; + + if (self.tur_head.frame > 6) + self.tur_head.frame = 0; + + return TRUE; + } + case TR_DEATH: + { + return TRUE; + } + case TR_SETUP: + { + self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE; + self.damage_flags |= TFL_DMG_HEADSHAKE; + self.firecheck_flags |= TFL_FIRECHECK_AFF; + self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE | TFL_AIM_SPLASH; + + turret_do_updates(self); + + return TRUE; + } + case TR_PRECACHE: + { + precache_model ("models/turrets/base.md3"); + precache_model ("models/turrets/plasmad.md3"); + return TRUE; + } + } + + return TRUE; +} + +#endif // SVQC +#ifdef CSQC +float t_plasma_dual(float req) +{ + switch(req) + { + case TR_SETUP: + { + return TRUE; + } + case TR_PRECACHE: + { + precache_model ("models/turrets/base.md3"); + precache_model ("models/turrets/plasmad.md3"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_TURRET diff --combined qcsrc/server/autocvars.qh index 21f6a712e,4d207955c..c0e897558 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@@ -260,6 -260,7 +260,7 @@@ float autocvar_g_balance_grapplehook_sp float autocvar_g_balance_grapplehook_speed_pull; float autocvar_g_balance_grapplehook_stretch; float autocvar_g_balance_grapplehook_damagedbycontents; + float autocvar_g_balance_grapplehook_refire; float autocvar_g_balance_grenadelauncher_bouncefactor; float autocvar_g_balance_grenadelauncher_bouncestop; float autocvar_g_balance_grenadelauncher_primary_ammo; @@@ -791,6 -792,10 +792,10 @@@ float autocvar_g_domination_disable_fra float autocvar_g_domination_point_amt; float autocvar_g_domination_point_fullbright; float autocvar_g_domination_point_leadlimit; + float autocvar_g_domination_roundbased; + float autocvar_g_domination_roundbased_point_limit; + float autocvar_g_domination_round_timelimit; + float autocvar_g_domination_warmup; #define autocvar_g_domination_point_limit cvar("g_domination_point_limit") float autocvar_g_domination_point_rate; float autocvar_g_domination_teams_override; @@@ -800,10 -805,13 +805,13 @@@ string autocvar_g_forced_team_otherwise string autocvar_g_forced_team_pink; string autocvar_g_forced_team_red; string autocvar_g_forced_team_yellow; + float autocvar_g_freezetag_frozen_damage_trigger; float autocvar_g_freezetag_frozen_force; float autocvar_g_freezetag_frozen_maxtime; float autocvar_g_freezetag_revive_falldamage; float autocvar_g_freezetag_revive_falldamage_health; + float autocvar_g_freezetag_revive_nade; + float autocvar_g_freezetag_revive_nade_health; float autocvar_g_freezetag_point_leadlimit; float autocvar_g_freezetag_point_limit; float autocvar_g_freezetag_revive_extra_size; @@@ -878,11 -886,11 +886,11 @@@ float autocvar_g_maxplayers_spectator_b float autocvar_g_maxpushtime; float autocvar_g_maxspeed; float autocvar_g_midair_shieldtime; - #define autocvar_g_minstagib cvar("g_minstagib") - float autocvar_g_minstagib_ammo_drop; - float autocvar_g_minstagib_extralives; - float autocvar_g_minstagib_speed_highspeed; - float autocvar_g_minstagib_invis_alpha; + #define autocvar_g_instagib cvar("g_instagib") + float autocvar_g_instagib_ammo_drop; + float autocvar_g_instagib_extralives; + float autocvar_g_instagib_speed_highspeed; + float autocvar_g_instagib_invis_alpha; #define autocvar_g_mirrordamage cvar("g_mirrordamage") #define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual") @@@ -965,6 -973,8 +973,8 @@@ float autocvar_g_spawnpoints_auto_move_ #define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime") #define autocvar_g_start_weapon_laser cvar("g_start_weapon_laser") float autocvar_g_tdm_team_spawns; + float autocvar_g_tdm_point_limit; + float autocvar_g_tdm_point_leadlimit; float autocvar_g_tdm_teams; float autocvar_g_tdm_teams_override; float autocvar_g_teamdamage_resetspeed; @@@ -992,6 -1002,41 +1002,6 @@@ float autocvar_g_turrets_nofire float autocvar_g_turrets_reloadcvars; float autocvar_g_turrets_targetscan_maxdelay; float autocvar_g_turrets_targetscan_mindelay; -float autocvar_g_turrets_unit_ewheel_speed_fast; -float autocvar_g_turrets_unit_ewheel_speed_slow; -float autocvar_g_turrets_unit_ewheel_speed_slower; -float autocvar_g_turrets_unit_ewheel_speed_stop; -float autocvar_g_turrets_unit_ewheel_turnrate; -float autocvar_g_turrets_unit_hellion_std_shot_speed_gain; -float autocvar_g_turrets_unit_hellion_std_shot_speed_max; -float autocvar_g_turrets_unit_hk_std_shot_speed; -float autocvar_g_turrets_unit_hk_std_shot_speed_accel; -float autocvar_g_turrets_unit_hk_std_shot_speed_accel2; -float autocvar_g_turrets_unit_hk_std_shot_speed_decel; -float autocvar_g_turrets_unit_hk_std_shot_speed_max; -float autocvar_g_turrets_unit_hk_std_shot_speed_turnrate; -float autocvar_g_turrets_unit_walker_speed_jump; -float autocvar_g_turrets_unit_walker_speed_roam; -float autocvar_g_turrets_unit_walker_speed_run; -float autocvar_g_turrets_unit_walker_speed_stop; -float autocvar_g_turrets_unit_walker_speed_swim; -float autocvar_g_turrets_unit_walker_speed_walk; -float autocvar_g_turrets_unit_walker_std_meele_dmg; -float autocvar_g_turrets_unit_walker_std_meele_force; -float autocvar_g_turrets_unit_walker_std_meele_range; -float autocvar_g_turrets_unit_walker_std_rocket_dmg; -float autocvar_g_turrets_unit_walker_std_rocket_force; -float autocvar_g_turrets_unit_walker_std_rocket_radius; -float autocvar_g_turrets_unit_walker_std_rocket_refire; -float autocvar_g_turrets_unit_walker_std_rocket_speed; -float autocvar_g_turrets_unit_walker_std_rocket_turnrate; -float autocvar_g_turrets_unit_walker_std_rockets_range; -float autocvar_g_turrets_unit_walker_std_rockets_range_min; -float autocvar_g_turrets_unit_walker_turn; -float autocvar_g_turrets_unit_walker_turn_walk; -float autocvar_g_turrets_unit_walker_turn_run; -float autocvar_g_turrets_unit_walker_turn_strafe; -float autocvar_g_turrets_unit_walker_turn_swim; float autocvar_g_use_ammunition; float autocvar_g_waypointeditor; float autocvar_g_waypointeditor_auto; @@@ -1070,6 -1115,7 +1080,7 @@@ float autocvar_sv_dodging_up_speed float autocvar_sv_dodging_wall_distance_threshold; float autocvar_sv_dodging_wall_dodging; float autocvar_sv_dodging_frozen; + float autocvar_sv_dodging_frozen_doubletap; float autocvar_sv_doublejump; float autocvar_sv_eventlog; float autocvar_sv_eventlog_console; @@@ -1120,6 -1166,11 +1131,11 @@@ float autocvar_sv_timeout_resumetime float autocvar_sv_vote_call; float autocvar_sv_vote_change; string autocvar_sv_vote_commands; + float autocvar_sv_vote_gametype; + float autocvar_sv_vote_gametype_timeout; + string autocvar_sv_vote_gametype_options; + float autocvar_sv_vote_gametype_keeptwotime; + float autocvar_sv_vote_gametype_default_current; float autocvar_sv_vote_limit; float autocvar_sv_vote_majority_factor; float autocvar_sv_vote_majority_factor_of_voted; @@@ -1186,6 -1237,7 +1202,7 @@@ float autocvar_g_physical_items_damagef float autocvar_g_physical_items_reset; float autocvar_g_monsters; float autocvar_g_monsters_edit; + float autocvar_g_monsters_sounds; float autocvar_g_monsters_think_delay; float autocvar_g_monsters_max; float autocvar_g_monsters_max_perplayer; @@@ -1209,7 -1261,10 +1226,10 @@@ float autocvar_g_touchexplode_damage float autocvar_g_touchexplode_edgedamage; float autocvar_g_touchexplode_force; float autocvar_g_invasion_round_timelimit; - #define autocvar_g_invasion_round_limit cvar("g_invasion_round_limit") + float autocvar_g_invasion_teams; + float autocvar_g_invasion_team_spawns; + float autocvar_g_invasion_spawnpoint_spawn_delay; + #define autocvar_g_invasion_point_limit cvar("g_invasion_point_limit") float autocvar_g_invasion_warmup; float autocvar_g_invasion_monster_count; float autocvar_g_invasion_zombies_only; @@@ -1223,6 -1278,8 +1243,8 @@@ float autocvar_g_random_gravity_negativ float autocvar_g_random_gravity_delay; float autocvar_g_nades; float autocvar_g_nades_spawn; + float autocvar_g_nades_spawn_count; + float autocvar_g_nades_client_select; float autocvar_g_nades_nade_lifetime; float autocvar_g_nades_nade_minforce; float autocvar_g_nades_nade_maxforce; @@@ -1233,6 -1290,44 +1255,44 @@@ float autocvar_g_nades_nade_edgedamage float autocvar_g_nades_nade_radius; float autocvar_g_nades_nade_force; float autocvar_g_nades_nade_newton_style; + float autocvar_g_nades_napalm_ball_count; + float autocvar_g_nades_napalm_ball_spread; + float autocvar_g_nades_napalm_ball_damage; + float autocvar_g_nades_napalm_ball_damageforcescale; + float autocvar_g_nades_napalm_ball_lifetime; + float autocvar_g_nades_napalm_ball_radius; + float autocvar_g_nades_napalm_blast; + float autocvar_g_nades_napalm_fountain_lifetime; + float autocvar_g_nades_napalm_fountain_delay; + float autocvar_g_nades_napalm_fountain_radius; + float autocvar_g_nades_napalm_fountain_damage; + float autocvar_g_nades_napalm_fountain_edgedamage; + float autocvar_g_nades_napalm_burntime; + float autocvar_g_nades_napalm_selfdamage; + float autocvar_g_nades_nade_type; + float autocvar_g_nades_bonus_type; + float autocvar_g_nades_bonus; + float autocvar_g_nades_bonus_onstrength; + float autocvar_g_nades_bonus_client_select; + float autocvar_g_nades_bonus_max; + float autocvar_g_nades_bonus_score_max; + float autocvar_g_nades_bonus_score_time; + float autocvar_g_nades_bonus_score_time_flagcarrier; + float autocvar_g_nades_bonus_score_minor; + float autocvar_g_nades_bonus_score_low; + float autocvar_g_nades_bonus_score_high; + float autocvar_g_nades_bonus_score_medium; + float autocvar_g_nades_bonus_score_spree; + float autocvar_g_nades_ice_freeze_time; + float autocvar_g_nades_ice_health; + float autocvar_g_nades_ice_explode; + float autocvar_g_nades_ice_teamcheck; + float autocvar_g_nades_heal_time; + float autocvar_g_nades_heal_rate; + float autocvar_g_nades_heal_friend; + float autocvar_g_nades_heal_foe; + string autocvar_g_nades_pokenade_monster_type; + float autocvar_g_nades_pokenade_monster_lifetime; float autocvar_g_campcheck_damage; float autocvar_g_campcheck_distance; float autocvar_g_campcheck_interval; @@@ -1243,3 -1338,33 +1303,33 @@@ float autocvar_g_spawn_near_teammate_ig float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death; float autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health; float autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath; + float autocvar_g_buffs_waypoint_distance; + float autocvar_g_buffs_randomize; + float autocvar_g_buffs_random_lifetime; + float autocvar_g_buffs_random_location; + float autocvar_g_buffs_random_location_attempts; + float autocvar_g_buffs_spawn_count; + float autocvar_g_buffs_replace_powerups; + float autocvar_g_buffs_cooldown_activate; + float autocvar_g_buffs_cooldown_respawn; + float autocvar_g_buffs_resistance_blockpercent; + float autocvar_g_buffs_medic_survive_chance; + float autocvar_g_buffs_medic_survive_health; + float autocvar_g_buffs_medic_rot; + float autocvar_g_buffs_medic_max; + float autocvar_g_buffs_medic_regen; + float autocvar_g_buffs_vengeance_damage_multiplier; + float autocvar_g_buffs_bash_force; + float autocvar_g_buffs_bash_force_self; + float autocvar_g_buffs_disability_time; + float autocvar_g_buffs_disability_speed; + float autocvar_g_buffs_disability_rate; + float autocvar_g_buffs_speed_speed; + float autocvar_g_buffs_speed_rate; + float autocvar_g_buffs_speed_damage_take; + float autocvar_g_buffs_speed_regen; + float autocvar_g_buffs_vampire_damage_steal; + float autocvar_g_buffs_invisible_alpha; + float autocvar_g_buffs_flight_gravity; + float autocvar_g_buffs_jump_height; + diff --combined qcsrc/server/g_damage.qc index 7af48956d,02488b8b1..1751e3b34 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@@ -549,6 -549,86 +549,86 @@@ void Obituary(entity attacker, entity i if(targ.killcount) { targ.killcount = 0; } } + void Ice_Think() + { + if(!self.owner.frozen || self.owner.iceblock != self) + { + remove(self); + return; + } + setorigin(self, self.owner.origin - '0 0 16'); + self.nextthink = time; + } + + void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint) + { + if(!IS_PLAYER(targ) && !(targ.flags & FL_MONSTER)) // only specified entities can be freezed + return; + + if(targ.frozen) + return; + + float targ_maxhealth = ((targ.flags & FL_MONSTER) ? targ.max_health : start_health); + + targ.frozen = frozen_type; + targ.revive_progress = ((frozen_type == 3) ? 1 : 0); + targ.health = ((frozen_type == 3) ? targ_maxhealth : 1); + targ.revive_speed = freeze_time; + + entity ice, head; + ice = spawn(); + ice.owner = targ; + ice.classname = "ice"; + ice.scale = targ.scale; + ice.think = Ice_Think; + ice.nextthink = time; + ice.frame = floor(random() * 21); // ice model has 20 different looking frames + setmodel(ice, "models/ice/ice.md3"); + ice.alpha = 1; + ice.colormod = Team_ColorRGB(targ.team); + ice.glowmod = ice.colormod; + targ.iceblock = ice; + targ.revival_time = 0; + + entity oldself; + oldself = self; + self = ice; + Ice_Think(); + self = oldself; + + RemoveGrapplingHook(targ); + + FOR_EACH_PLAYER(head) + if(head.hook.aiment == targ) + RemoveGrapplingHook(head); + + // add waypoint + if(show_waypoint) + WaypointSprite_Spawn("frozen", 0, 0, targ, '0 0 64', world, targ.team, targ, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1'); + } + + void Unfreeze (entity targ) + { + if(targ.frozen && targ.frozen != 3) // only reset health if target was frozen + targ.health = ((IS_PLAYER(targ)) ? start_health : targ.max_health); + + entity head; + targ.frozen = 0; + targ.revive_progress = 0; + targ.revival_time = time; + + WaypointSprite_Kill(targ.waypointsprite_attached); + + FOR_EACH_PLAYER(head) + if(head.hook.aiment == targ) + RemoveGrapplingHook(head); + + // remove the ice block + if(targ.iceblock) + remove(targ.iceblock); + targ.iceblock = world; + } + // these are updated by each Damage call for use in button triggering and such entity damage_targ; entity damage_inflictor; @@@ -690,7 -770,63 +770,63 @@@ void Damage (entity targ, entity inflic mirrordamage = frag_mirrordamage; force = frag_force; - if (!g_minstagib) + if(targ.frozen) + if(deathtype != DEATH_HURTTRIGGER && deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_AUTOTEAMCHANGE) + { + if(autocvar_g_freezetag_revive_falldamage > 0) + if(deathtype == DEATH_FALL) + if(damage >= autocvar_g_freezetag_revive_falldamage) + { + Unfreeze(targ); + targ.health = autocvar_g_freezetag_revive_falldamage_health; + pointparticles(particleeffectnum("iceorglass"), targ.origin, '0 0 0', 3); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, targ.netname); + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF); + } + + damage = 0; + force *= autocvar_g_freezetag_frozen_force; + } + + if(targ.frozen && deathtype == DEATH_HURTTRIGGER && !autocvar_g_freezetag_frozen_damage_trigger) + { + pointparticles(particleeffectnum("teleport"), targ.origin, '0 0 0', 1); + + entity oldself = self; + self = targ; + entity spot = SelectSpawnPoint (FALSE); + + if(spot) + { + damage = 0; + self.deadflag = DEAD_NO; + + self.angles = spot.angles; + + self.effects = 0; + self.effects |= EF_TELEPORT_BIT; + + self.angles_z = 0; // never spawn tilted even if the spot says to + self.fixangle = TRUE; // turn this way immediately + self.velocity = '0 0 0'; + self.avelocity = '0 0 0'; + self.punchangle = '0 0 0'; + self.punchvector = '0 0 0'; + self.oldvelocity = self.velocity; + + self.spawnorigin = spot.origin; + setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24)); + // don't reset back to last position, even if new position is stuck in solid + self.oldorigin = self.origin; + self.prevorigin = self.origin; + + pointparticles(particleeffectnum("teleport"), self.origin, '0 0 0', 1); + } + + self = oldself; + } + + if(!g_instagib) { // apply strength multiplier if (attacker.items & IT_STRENGTH) @@@ -713,12 -849,7 +849,7 @@@ } if (targ == attacker) - { - if(g_cts && !autocvar_g_cts_selfdamage) - damage = 0; - else - damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself - } + damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself // count the damage if(attacker) @@@ -732,7 -863,7 +863,7 @@@ else victim = targ; - if(IS_PLAYER(victim) || victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET || victim.flags & FL_MONSTER) + if(IS_PLAYER(victim) || ((victim.turret_flags & TUR_FLAG_ISTURRET) && victim.active == ACTIVE_ACTIVE) || (victim.flags & FL_MONSTER)) { if(DIFF_TEAM(victim, attacker)) { @@@ -743,7 -874,7 +874,7 @@@ if(victim.BUTTON_CHAT) attacker.typehitsound += 1; else - attacker.hitsound += 1; + attacker.damage_dealt += damage; } damage_goodhits += 1; @@@ -1200,23 -1331,24 +1331,24 @@@ void Fire_ApplyDamage(entity e e.fire_endtime = 0; // ice stops fire - if(e.freezetag_frozen) + if(e.frozen) e.fire_endtime = 0; t = min(frametime, e.fire_endtime - time); d = e.fire_damagepersec * t; - hi = e.fire_owner.hitsound; + hi = e.fire_owner.damage_dealt; ty = e.fire_owner.typehitsound; Damage(e, e, e.fire_owner, d, e.fire_deathtype, e.origin, '0 0 0'); if(e.fire_hitsound && e.fire_owner) { - e.fire_owner.hitsound = hi; + e.fire_owner.damage_dealt = hi; e.fire_owner.typehitsound = ty; } e.fire_hitsound = TRUE; if (!IS_INDEPENDENT_PLAYER(e)) + if(!e.frozen) FOR_EACH_PLAYER(other) if(e != other) { if(IS_PLAYER(other)) diff --combined qcsrc/server/g_world.qc index f9de06c1b,7eda0103c..dd79c8bbb --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@@ -55,7 -55,6 +55,6 @@@ const float SPAWNFLAG_NO_WAYPOINTS_FOR_ string redirection_target; float world_initialized; - string GetMapname(); string GetGametype(); void GotoNextMap(float reinit); void ShuffleMaplist(); @@@ -216,7 -215,6 +215,6 @@@ void cvar_changes_init( // private BADCVAR("developer"); BADCVAR("log_dest_udp"); - BADCVAR("log_file"); BADCVAR("net_address"); BADCVAR("net_address_ipv6"); BADCVAR("port"); @@@ -237,6 -235,7 +235,7 @@@ BADPREFIX("g_playerstats_"); BADPREFIX("g_respawn_ghosts"); BADPREFIX("g_voice_flood_"); + BADPREFIX("log_file"); BADPREFIX("rcon_"); BADPREFIX("sv_allowdownloads"); BADPREFIX("sv_autodemo"); @@@ -421,7 -420,7 +420,7 @@@ BADPREFIX("sv_ready_restart_"); // mutators that announce themselves properly to the server browser - BADCVAR("g_minstagib"); + BADCVAR("g_instagib"); BADCVAR("g_new_toys"); BADCVAR("g_nix"); BADCVAR("g_grappling_hook"); @@@ -542,11 -541,11 +541,12 @@@ void spawnfunc___init_dedicated_server( // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterTurrets); CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); MapInfo_Enumerate(); MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); @@@ -592,11 -591,11 +592,12 @@@ void spawnfunc_worldspawn (void // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterTurrets); CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid)); @@@ -787,7 -786,7 +788,7 @@@ addstat(STAT_WEAPON_CLIPLOAD, AS_INT, clip_load); addstat(STAT_WEAPON_CLIPSIZE, AS_INT, clip_size); addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup); - addstat(STAT_HIT_TIME, AS_FLOAT, hit_time); + addstat(STAT_DAMAGE_DEALT_TOTAL, AS_INT, damage_dealt_total); addstat(STAT_TYPEHIT_TIME, AS_FLOAT, typehit_time); addstat(STAT_LAYED_MINES, AS_INT, minelayer_mines); @@@ -796,6 -795,10 +797,10 @@@ addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load); + // freeze attacks + addstat(STAT_FROZEN, AS_INT, frozen); + addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress); + // g_movementspeed hack addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw); addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed); @@@ -898,7 -901,6 +903,6 @@@ string GetGametype( return MapInfo_Type_ToString(MapInfo_LoadedGametype); } - string getmapname_stored; string GetMapname() { return mapname; @@@ -1223,13 -1225,27 +1227,27 @@@ float DoNextMapOverride(float reinit return TRUE; } if(autocvar_nextmap != "") - if(MapInfo_CheckMap(autocvar_nextmap)) + { + string m; + m = GameTypeVote_MapInfo_FixName(autocvar_nextmap); + cvar_set("nextmap",m); + + if(!m || gametypevote) + return FALSE; + if(autocvar_sv_vote_gametype) + { + Map_Goto_SetStr(m); + return FALSE; + } + + if(MapInfo_CheckMap(m)) { - Map_Goto_SetStr(autocvar_nextmap); + Map_Goto_SetStr(m); Map_Goto(reinit); alreadychangedlevel = TRUE; return TRUE; } + } if(!reinit && autocvar_lastlevel) { cvar_settemp_restore(); @@@ -1266,9 -1282,6 +1284,6 @@@ When the player presses attack or jump ============ */ .float autoscreenshot; - void() MapVote_Start; - void() MapVote_Think; - float mapvote_initialized; void IntermissionThink() { FixIntermissionClient(self); @@@ -1578,7 -1591,7 +1593,7 @@@ float InitiateSuddenDeath( // - for this timelimit_overtime needs to be >0 of course // - also check the winning condition calculated in the previous frame and only add normal overtime // again, if at the point at which timelimit would be extended again, still no winner was found - if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) + if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) { return 1; // need to call InitiateOvertime later } @@@ -2033,17 -2046,6 +2048,6 @@@ void CheckRules_World( SetDefaultAlpha(); - /* - MapVote_Think should now do that part - if (intermission_running) - if (time >= intermission_exittime + 60) - { - if(!DoNextMapOverride()) - GotoNextMap(); - return; - } - */ - if (gameover) // someone else quit the game already { if(player_count == 0) // Nobody there? Then let's go to the next map @@@ -2205,517 -2207,14 +2209,14 @@@ } } - float mapvote_nextthink; - float mapvote_initialized; - float mapvote_keeptwotime; - float mapvote_timeout; - string mapvote_message; - #define MAPVOTE_SCREENSHOT_DIRS_COUNT 4 - string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT]; - float mapvote_screenshot_dirs_count; - - float mapvote_count; - float mapvote_count_real; - string mapvote_maps[MAPVOTE_COUNT]; - float mapvote_maps_screenshot_dir[MAPVOTE_COUNT]; - string mapvote_maps_pakfile[MAPVOTE_COUNT]; - float mapvote_maps_suggested[MAPVOTE_COUNT]; - string mapvote_suggestions[MAPVOTE_COUNT]; - float mapvote_suggestion_ptr; - float mapvote_voters; - float mapvote_selections[MAPVOTE_COUNT]; - float mapvote_run; - float mapvote_detail; - float mapvote_abstain; - .float mapvote; - - void MapVote_ClearAllVotes() - { - FOR_EACH_CLIENT(other) - other.mapvote = 0; - } - - string MapVote_Suggest(string m) + string GotoMap(string m) { - float i; - if(m == "") - return "That's not how to use this command."; - if(!autocvar_g_maplist_votable_suggestions) - return "Suggestions are not accepted on this server."; - if(mapvote_initialized) - return "Can't suggest - voting is already in progress!"; - m = MapInfo_FixName(m); + m = GameTypeVote_MapInfo_FixName(m); if (!m) return "The map you suggested is not available on this server."; - if(!autocvar_g_maplist_votable_suggestions_override_mostrecent) - if(Map_IsRecent(m)) - return "This server does not allow for recent maps to be played again. Please be patient for some rounds."; - + if (!autocvar_sv_vote_gametype) if(!MapInfo_CheckMap(m)) return "The map you suggested does not support the current game mode."; - for(i = 0; i < mapvote_suggestion_ptr; ++i) - if(mapvote_suggestions[i] == m) - return "This map was already suggested."; - if(mapvote_suggestion_ptr >= MAPVOTE_COUNT) - { - i = floor(random() * mapvote_suggestion_ptr); - } - else - { - i = mapvote_suggestion_ptr; - mapvote_suggestion_ptr += 1; - } - if(mapvote_suggestions[i] != "") - strunzone(mapvote_suggestions[i]); - mapvote_suggestions[i] = strzone(m); - if(autocvar_sv_eventlog) - GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid))); - return strcat("Suggestion of ", m, " accepted."); - } - - void MapVote_AddVotable(string nextMap, float isSuggestion) - { - float j, i, o; - string pakfile, mapfile; - - if(nextMap == "") - return; - for(j = 0; j < mapvote_count; ++j) - if(mapvote_maps[j] == nextMap) - return; - // suggestions might be no longer valid/allowed after gametype switch! - if(isSuggestion) - if(!MapInfo_CheckMap(nextMap)) - return; - mapvote_maps[mapvote_count] = strzone(nextMap); - mapvote_maps_suggested[mapvote_count] = isSuggestion; - - pakfile = string_null; - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) - { - mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]); - pakfile = whichpack(strcat(mapfile, ".tga")); - if(pakfile == "") - pakfile = whichpack(strcat(mapfile, ".jpg")); - if(pakfile == "") - pakfile = whichpack(strcat(mapfile, ".png")); - if(pakfile != "") - break; - } - if(i >= mapvote_screenshot_dirs_count) - i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server? - for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1) - pakfile = substring(pakfile, o, -1); - - mapvote_maps_screenshot_dir[mapvote_count] = i; - mapvote_maps_pakfile[mapvote_count] = strzone(pakfile); - - mapvote_count += 1; - } - - void MapVote_Spawn(); - void MapVote_Init() - { - float i; - float nmax, smax; - - MapVote_ClearAllVotes(); - - mapvote_count = 0; - mapvote_detail = !autocvar_g_maplist_votable_nodetail; - mapvote_abstain = autocvar_g_maplist_votable_abstain; - - if(mapvote_abstain) - nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable); - else - nmax = min(MAPVOTE_COUNT, autocvar_g_maplist_votable); - smax = min3(nmax, autocvar_g_maplist_votable_suggestions, mapvote_suggestion_ptr); - - // we need this for AddVotable, as that cycles through the screenshot dirs - mapvote_screenshot_dirs_count = tokenize_console(autocvar_g_maplist_votable_screenshot_dir); - if(mapvote_screenshot_dirs_count == 0) - mapvote_screenshot_dirs_count = tokenize_console("maps levelshots"); - mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT); - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) - mapvote_screenshot_dirs[i] = strzone(argv(i)); - - if(mapvote_suggestion_ptr) - for(i = 0; i < 100 && mapvote_count < smax; ++i) - MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE); - - for(i = 0; i < 100 && mapvote_count < nmax; ++i) - MapVote_AddVotable(GetNextMap(), FALSE); - - if(mapvote_count == 0) - { - bprint( "Maplist contains no single playable map! Resetting it to default map list.\n" ); - cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags())); - if(autocvar_g_maplist_shuffle) - ShuffleMaplist(); - localcmd("\nmenu_cmd sync\n"); - for(i = 0; i < 100 && mapvote_count < nmax; ++i) - MapVote_AddVotable(GetNextMap(), FALSE); - } - - mapvote_count_real = mapvote_count; - if(mapvote_abstain) - MapVote_AddVotable("don't care", 0); - - //dprint("mapvote count is ", ftos(mapvote_count), "\n"); - - mapvote_keeptwotime = time + autocvar_g_maplist_votable_keeptwotime; - mapvote_timeout = time + autocvar_g_maplist_votable_timeout; - if(mapvote_count_real < 3 || mapvote_keeptwotime <= time) - mapvote_keeptwotime = 0; - mapvote_message = "Choose a map and press its key!"; - - MapVote_Spawn(); - } - - void MapVote_SendPicture(float id) - { - msg_entity = self; - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_PICTURE); - WriteByte(MSG_ONE, id); - WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072); - } - - float MapVote_GetMapMask() - { - float mask, i, power; - mask = 0; - for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2) - if(mapvote_maps[i] != "") - mask |= power; - return mask; - } - - entity mapvote_ent; - float MapVote_SendEntity(entity to, float sf) - { - float i; - - if(sf & 1) - sf &= ~2; // if we send 1, we don't need to also send 2 - - WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE); - WriteByte(MSG_ENTITY, sf); - - if(sf & 1) - { - // flag 1 == initialization - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) - WriteString(MSG_ENTITY, mapvote_screenshot_dirs[i]); - WriteString(MSG_ENTITY, ""); - WriteByte(MSG_ENTITY, mapvote_count); - WriteByte(MSG_ENTITY, mapvote_abstain); - WriteByte(MSG_ENTITY, mapvote_detail); - WriteCoord(MSG_ENTITY, mapvote_timeout); - if(mapvote_count <= 8) - WriteByte(MSG_ENTITY, MapVote_GetMapMask()); - else - WriteShort(MSG_ENTITY, MapVote_GetMapMask()); - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - { - if(mapvote_abstain && i == mapvote_count - 1) - { - WriteString(MSG_ENTITY, ""); // abstain needs no text - WriteString(MSG_ENTITY, ""); // abstain needs no pack - WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir - } - else - { - WriteString(MSG_ENTITY, mapvote_maps[i]); - WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]); - WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]); - } - } - } - - if(sf & 2) - { - // flag 2 == update of mask - if(mapvote_count <= 8) - WriteByte(MSG_ENTITY, MapVote_GetMapMask()); - else - WriteShort(MSG_ENTITY, MapVote_GetMapMask()); - } - - if(sf & 4) - { - if(mapvote_detail) - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - WriteByte(MSG_ENTITY, mapvote_selections[i]); - - WriteByte(MSG_ENTITY, to.mapvote); - } - - return TRUE; - } - - void MapVote_Spawn() - { - Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity); - } - - void MapVote_TouchMask() - { - mapvote_ent.SendFlags |= 2; - } - - void MapVote_TouchVotes(entity voter) - { - mapvote_ent.SendFlags |= 4; - } - - float MapVote_Finished(float mappos) - { - string result; - float i; - float didntvote; - - if(autocvar_sv_eventlog) - { - result = strcat(":vote:finished:", mapvote_maps[mappos]); - result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::"); - didntvote = mapvote_voters; - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - { - didntvote -= mapvote_selections[i]; - if(i != mappos) - { - result = strcat(result, ":", mapvote_maps[i]); - result = strcat(result, ":", ftos(mapvote_selections[i])); - } - } - result = strcat(result, ":didn't vote:", ftos(didntvote)); - - GameLogEcho(result); - if(mapvote_maps_suggested[mappos]) - GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos])); - } - - FOR_EACH_REALCLIENT(other) - FixClientCvars(other); - - Map_Goto_SetStr(mapvote_maps[mappos]); - Map_Goto(0); - alreadychangedlevel = TRUE; - return TRUE; - } - void MapVote_CheckRules_1() - { - float i; - - for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "") - { - //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n"); - mapvote_selections[i] = 0; - } - - mapvote_voters = 0; - FOR_EACH_REALCLIENT(other) - { - ++mapvote_voters; - if(other.mapvote) - { - i = other.mapvote - 1; - //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n"); - mapvote_selections[i] = mapvote_selections[i] + 1; - } - } - } - - float MapVote_CheckRules_2() - { - float i; - float firstPlace, secondPlace; - float firstPlaceVotes, secondPlaceVotes; - float mapvote_voters_real; - string result; - - if(mapvote_count_real == 1) - return MapVote_Finished(0); - - mapvote_voters_real = mapvote_voters; - if(mapvote_abstain) - mapvote_voters_real -= mapvote_selections[mapvote_count - 1]; - - RandomSelection_Init(); - for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "") - RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]); - firstPlace = RandomSelection_chosen_float; - firstPlaceVotes = RandomSelection_best_priority; - //dprint("First place: ", ftos(firstPlace), "\n"); - //dprint("First place votes: ", ftos(firstPlaceVotes), "\n"); - - RandomSelection_Init(); - for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "") - if(i != firstPlace) - RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]); - secondPlace = RandomSelection_chosen_float; - secondPlaceVotes = RandomSelection_best_priority; - //dprint("Second place: ", ftos(secondPlace), "\n"); - //dprint("Second place votes: ", ftos(secondPlaceVotes), "\n"); - - if(firstPlace == -1) - error("No first place in map vote... WTF?"); - - if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes) - return MapVote_Finished(firstPlace); - - if(mapvote_keeptwotime) - if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes) - { - float didntvote; - MapVote_TouchMask(); - mapvote_message = "Now decide between the TOP TWO!"; - mapvote_keeptwotime = 0; - result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]); - result = strcat(result, ":", ftos(firstPlaceVotes)); - result = strcat(result, ":", mapvote_maps[secondPlace]); - result = strcat(result, ":", ftos(secondPlaceVotes), "::"); - didntvote = mapvote_voters; - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - { - didntvote -= mapvote_selections[i]; - if(i != firstPlace) - if(i != secondPlace) - { - result = strcat(result, ":", mapvote_maps[i]); - result = strcat(result, ":", ftos(mapvote_selections[i])); - if(i < mapvote_count_real) - { - strunzone(mapvote_maps[i]); - mapvote_maps[i] = ""; - strunzone(mapvote_maps_pakfile[i]); - mapvote_maps_pakfile[i] = ""; - } - } - } - result = strcat(result, ":didn't vote:", ftos(didntvote)); - if(autocvar_sv_eventlog) - GameLogEcho(result); - } - - return FALSE; - } - void MapVote_Tick() - { - float keeptwo; - float totalvotes; - - keeptwo = mapvote_keeptwotime; - MapVote_CheckRules_1(); // count - if(MapVote_CheckRules_2()) // decide - return; - - totalvotes = 0; - FOR_EACH_REALCLIENT(other) - { - // hide scoreboard again - if(other.health != 2342) - { - other.health = 2342; - other.impulse = 0; - if(IS_REAL_CLIENT(other)) - { - msg_entity = other; - WriteByte(MSG_ONE, SVC_FINALE); - WriteString(MSG_ONE, ""); - } - } - - // clear possibly invalid votes - if(mapvote_maps[other.mapvote - 1] == "") - other.mapvote = 0; - // use impulses as new vote - if(other.impulse >= 1 && other.impulse <= mapvote_count) - if(mapvote_maps[other.impulse - 1] != "") - { - other.mapvote = other.impulse; - MapVote_TouchVotes(other); - } - other.impulse = 0; - - if(other.mapvote) - ++totalvotes; - } - - MapVote_CheckRules_1(); // just count - } - void MapVote_Start() - { - if(mapvote_run) - return; - - // wait for stats to be sent first - if(!playerstats_waitforme) - return; - - MapInfo_Enumerate(); - if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1)) - mapvote_run = TRUE; - } - void MapVote_Think() - { - if(!mapvote_run) - return; - - if(alreadychangedlevel) - return; - - if(time < mapvote_nextthink) - return; - //dprint("tick\n"); - - mapvote_nextthink = time + 0.5; - - if(!mapvote_initialized) - { - if(autocvar_rescan_pending == 1) - { - cvar_set("rescan_pending", "2"); - localcmd("fs_rescan\nrescan_pending 3\n"); - return; - } - else if(autocvar_rescan_pending == 2) - { - return; - } - else if(autocvar_rescan_pending == 3) - { - // now build missing mapinfo files - if(!MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1)) - return; - - // we're done, start the timer - cvar_set("rescan_pending", "0"); - } - - mapvote_initialized = TRUE; - if(DoNextMapOverride(0)) - return; - if(!autocvar_g_maplist_votable || player_count <= 0) - { - GotoNextMap(0); - return; - } - MapVote_Init(); - } - - MapVote_Tick(); - } - - string GotoMap(string m) - { - if(!MapInfo_CheckMap(m)) - return "The map you chose is not available on this server."; cvar_set("nextmap", m); cvar_set("timelimit", "-1"); if(mapvote_initialized || alreadychangedlevel) @@@ -2732,22 -2231,26 +2233,26 @@@ void EndFrame() { + anticheat_endframe(); + float altime; FOR_EACH_REALCLIENT(self) { + self.damage_dealt_total = 0; + if(IS_SPEC(self)) { if(self.enemy.typehitsound) self.typehit_time = time; - else if(self.enemy.hitsound) - self.hit_time = time; + else if(self.enemy.damage_dealt) + self.damage_dealt_total = ceil(self.enemy.damage_dealt); } else { if(self.typehitsound) self.typehit_time = time; - else if(self.hitsound) - self.hit_time = time; + else if(self.damage_dealt) + self.damage_dealt_total = ceil(self.damage_dealt); } } altime = time + frametime * (1 + autocvar_g_antilag_nudge); @@@ -2758,10 -2261,12 +2263,12 @@@ // needed! FOR_EACH_CLIENT(self) { - self.hitsound = FALSE; self.typehitsound = FALSE; + self.damage_dealt = 0; antilag_record(self, altime); } + FOR_EACH_MONSTER(self) + antilag_record(self, altime); } diff --combined qcsrc/server/miscfunctions.qc index 0eb71b93c,fc9e84e58..d57c5b29a --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@@ -708,7 -708,7 +708,7 @@@ void readplayerstartcvars( { // forcibly turn off weaponarena } - else if (s == "all") + else if (s == "all" || s == "1") { g_weaponarena = 1; g_weaponarena_list = "All Weapons"; @@@ -904,34 -904,11 +904,11 @@@ float sv_autotaunt float sv_taunt; string GetGametype(); // g_world.qc + void mutators_add(); // mutators.qc void readlevelcvars(void) { // load mutators - #define CHECK_MUTATOR_ADD(mut_cvar,mut_name,dependence) \ - { if(cvar(mut_cvar) && dependence) { MUTATOR_ADD(mut_name); } } - - CHECK_MUTATOR_ADD("g_dodging", mutator_dodging, 1); - CHECK_MUTATOR_ADD("g_spawn_near_teammate", mutator_spawn_near_teammate, teamplay); - CHECK_MUTATOR_ADD("g_physical_items", mutator_physical_items, 1); - CHECK_MUTATOR_ADD("g_touchexplode", mutator_touchexplode, 1); - CHECK_MUTATOR_ADD("g_minstagib", mutator_minstagib, 1); - CHECK_MUTATOR_ADD("g_invincible_projectiles", mutator_invincibleprojectiles, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_new_toys", mutator_new_toys, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_nix", mutator_nix, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_rocket_flying", mutator_rocketflying, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_vampire", mutator_vampire, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_superspectate", mutator_superspec, 1); - CHECK_MUTATOR_ADD("g_pinata", mutator_pinata, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_midair", mutator_midair, 1); - CHECK_MUTATOR_ADD("g_bloodloss", mutator_bloodloss, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_random_gravity", mutator_random_gravity, 1); - CHECK_MUTATOR_ADD("g_multijump", mutator_multijump, 1); - CHECK_MUTATOR_ADD("g_melee_only", mutator_melee_only, !cvar("g_minstagib")); - CHECK_MUTATOR_ADD("g_nades", mutator_nades, 1); - CHECK_MUTATOR_ADD("g_sandbox", sandbox, 1); - CHECK_MUTATOR_ADD("g_campcheck", mutator_campcheck, 1); - - #undef CHECK_MUTATOR_ADD + mutators_add(); if(cvar("sv_allow_fullbright")) serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT; @@@ -952,13 -929,11 +929,11 @@@ g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow"); g_bugrigs_steer = cvar("g_bugrigs_steer"); - g_minstagib = cvar("g_minstagib"); + g_instagib = cvar("g_instagib"); sv_clones = cvar("sv_clones"); sv_foginterval = cvar("sv_foginterval"); g_cloaked = cvar("g_cloaked"); - if(g_cts) - g_cloaked = 1; // always enable cloak in CTS g_footsteps = cvar("g_footsteps"); g_grappling_hook = cvar("g_grappling_hook"); g_jetpack = cvar("g_jetpack"); @@@ -1082,15 -1057,6 +1057,6 @@@ float sound_allowed(float dest, entity return TRUE; } - #ifdef COMPAT_XON010_CHANNELS - void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8; - void sound(entity e, float chan, string samp, float vol, float atten) - { - if (!sound_allowed(MSG_BROADCAST, e)) - return; - builtin_sound(e, chan, samp, vol, atten); - } - #else #undef sound void sound(entity e, float chan, string samp, float vol, float atten) { @@@ -1098,7 -1064,6 +1064,6 @@@ return; sound7(e, chan, samp, vol, atten, 0, 0); } - #endif void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten) { @@@ -1303,7 -1268,13 +1268,8 @@@ void precache( { // gamemode related things precache_model ("models/misc/chatbubble.spr"); + precache_model("models/ice/ice.md3"); -#ifdef TTURRETS_ENABLED - if (autocvar_g_turrets) - turrets_precash(); -#endif - // Precache all player models if desired if (autocvar_sv_precacheplayermodels) { @@@ -1821,82 -1792,6 +1787,6 @@@ string uid2name(string myuid) return s; } - float race_readTime(string map, float pos) - { - string rr; - if(g_cts) - rr = CTS_RECORD; - else - rr = RACE_RECORD; - - return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos)))); - } - - string race_readUID(string map, float pos) - { - string rr; - if(g_cts) - rr = CTS_RECORD; - else - rr = RACE_RECORD; - - return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))); - } - - float race_readPos(string map, float t) { - float i; - for (i = 1; i <= RANKINGS_CNT; ++i) - if (race_readTime(map, i) == 0 || race_readTime(map, i) > t) - return i; - - return 0; // pos is zero if unranked - } - - void race_writeTime(string map, float t, string myuid) - { - string rr; - if(g_cts) - rr = CTS_RECORD; - else - rr = RACE_RECORD; - - float newpos; - newpos = race_readPos(map, t); - - float i, prevpos = 0; - for(i = 1; i <= RANKINGS_CNT; ++i) - { - if(race_readUID(map, i) == myuid) - prevpos = i; - } - if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs - for (i = prevpos; i > newpos; --i) { - db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1))); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1)); - } - } else { // player has no ranked record yet - for (i = RANKINGS_CNT; i > newpos; --i) { - db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1))); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1)); - } - } - - // store new time itself - db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t)); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid); - } - - string race_readName(string map, float pos) - { - string rr; - if(g_cts) - rr = CTS_RECORD; - else - rr = RACE_RECORD; - - return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)))); - } - float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance) { float m, i; diff --combined qcsrc/server/mutators/gamemode_assault.qc index 23f95b746,1eb2b77cb..00455eb79 --- a/qcsrc/server/mutators/gamemode_assault.qc +++ b/qcsrc/server/mutators/gamemode_assault.qc @@@ -170,6 -170,7 +170,6 @@@ void assault_roundstart_use( activator = self; SUB_UseTargets(); -#ifdef TTURRETS_ENABLED entity ent, oldself; //(Re)spawn all turrets @@@ -185,11 -186,12 +185,11 @@@ self = ent; // Dubbles as teamchange - turret_stdproc_respawn(); + turret_respawn(); ent = find(ent, classname, "turret_main"); } self = oldself; -#endif } void assault_wall_think() @@@ -563,7 -565,7 +563,7 @@@ MUTATOR_DEFINITION(gamemode_assault MUTATOR_HOOK(PlayerSpawn, assault_PlayerSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(TurretSpawn, assault_TurretSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(VehicleSpawn, assault_VehicleSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(HavocBot_ChooseRule, assault_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(HavocBot_ChooseRole, assault_BotRoles, CBC_ORDER_ANY); MUTATOR_ONADD { diff --combined qcsrc/server/progs.src index 14902a8a3,288b24775..1120eda51 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@@ -13,8 -13,11 +13,11 @@@ sys-post.q ../warpzonelib/server.qh ../common/constants.qh + ../common/stats.qh ../common/teams.qh ../common/util.qh + ../common/nades.qh + ../common/buffs.qh ../common/test.qh ../common/counting.qh ../common/items.qh @@@ -37,26 -40,10 +40,14 @@@ defs.qh // Should rename this, it has ../common/notifications.qh // must be after autocvars ../common/deathtypes.qh // must be after notifications +../common/turrets/config.qh +../common/turrets/turrets.qh +../common/turrets/sv_turrets.qh +../common/turrets/util.qc + - mutators/base.qh - mutators/mutators.qh - mutators/gamemode_assault.qh - mutators/gamemode_ca.qh - mutators/gamemode_ctf.qh - mutators/gamemode_domination.qh - mutators/gamemode_keyhunt.qh // TODO fix this - mutators/gamemode_keepaway.qh - mutators/gamemode_nexball.qh - mutators/gamemode_lms.qh - mutators/gamemode_invasion.qh - mutators/mutator_dodging.qh - mutators/mutator_nades.qh + mutators/mutators_include.qh -//// tZork Turrets //// -tturrets/include/turrets_early.qh +//// tZork Vehicles //// vehicles/vehicles_def.qh campaign.qh @@@ -92,6 -79,8 +83,8 @@@ scores.q spawnpoints.qh + mapvoting.qh + ipban.qh race.qh @@@ -110,6 -99,8 +103,8 @@@ scores_rules.q miscfunctions.qc + mutators/mutators.qc + waypointsprites.qc bot/bot.qc @@@ -135,6 -126,8 +130,8 @@@ pathlib/pathlib.q g_world.qc g_casings.qc + mapvoting.qc + t_jumppads.qc t_teleporters.qc @@@ -202,7 -195,8 +199,7 @@@ t_quake.q race.qc -//// tZork Turrets //// -tturrets/include/turrets.qh +//// tZork Vehicles //// vehicles/vehicles.qh scores.qc @@@ -217,6 -211,9 +214,9 @@@ target_music.q ../common/items.qc + ../common/nades.qc + ../common/buffs.qc + accuracy.qc ../csqcmodellib/sv_model.qc @@@ -232,49 -229,12 +232,18 @@@ round_handler.q ../common/explosion_equation.qc +../common/turrets/sv_turrets.qc +../common/turrets/config.qc +../common/turrets/turrets.qc +../common/turrets/checkpoint.qc +../common/turrets/targettrigger.qc + ../common/monsters/sv_monsters.qc ../common/monsters/monsters.qc ../common/monsters/spawn.qc - mutators/base.qc - mutators/gamemode_assault.qc - mutators/gamemode_ca.qc - mutators/gamemode_ctf.qc - mutators/gamemode_domination.qc - mutators/gamemode_freezetag.qc - mutators/gamemode_keyhunt.qc - mutators/gamemode_keepaway.qc - mutators/gamemode_nexball.qc - mutators/gamemode_onslaught.qc - mutators/gamemode_lms.qc - mutators/gamemode_invasion.qc - mutators/mutator_invincibleproj.qc - mutators/mutator_new_toys.qc - mutators/mutator_nix.qc - mutators/mutator_dodging.qc - mutators/mutator_rocketflying.qc - mutators/mutator_vampire.qc - mutators/mutator_spawn_near_teammate.qc - mutators/mutator_physical_items.qc - mutators/sandbox.qc - mutators/mutator_superspec.qc - mutators/mutator_minstagib.qc - mutators/mutator_touchexplode.qc - mutators/mutator_pinata.qc - mutators/mutator_midair.qc - mutators/mutator_bloodloss.qc - mutators/mutator_random_gravity.qc - mutators/mutator_multijump.qc - mutators/mutator_melee_only.qc - mutators/mutator_nades.qc - mutators/mutator_campcheck.qc + mutators/mutators_include.qc ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc diff --combined qcsrc/server/t_teleporters.qc index 94f690f71,6e7c35b6a..230d20dc1 --- a/qcsrc/server/t_teleporters.qc +++ b/qcsrc/server/t_teleporters.qc @@@ -209,7 -209,7 +209,7 @@@ void Teleport_Touch (void if(!other.vehicle.teleportable) return; - if(other.turrcaps_flags & TFL_TURRCAPS_ISTURRET) + if(other.turret_flags & TUR_FLAG_ISTURRET) return; if(other.deadflag != DEAD_NO) @@@ -338,6 -338,12 +338,12 @@@ void spawnfunc_trigger_teleport (void void WarpZone_PostTeleportPlayer_Callback(entity pl) { UpdateCSQCProjectileAfterTeleport(pl); + { + entity oldself = self; + self = pl; + anticheat_fixangle(); + self = oldself; + } // "disown" projectiles after teleport if(pl.owner) if(pl.owner == pl.realowner)