]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Initial medal code port
authorz411 <z411@omaera.org>
Wed, 21 Jun 2023 18:16:18 +0000 (14:16 -0400)
committerz411 <z411@omaera.org>
Wed, 21 Jun 2023 18:16:18 +0000 (14:16 -0400)
19 files changed:
qcsrc/client/hud/panel/centerprint.qc
qcsrc/client/hud/panel/centerprint.qh
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc
qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qh
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
qcsrc/common/notifications/all.inc
qcsrc/common/notifications/all.qc
qcsrc/common/notifications/all.qh
qcsrc/common/scores.qh
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/server/client.qh
qcsrc/server/damage.qc
qcsrc/server/damage.qh
qcsrc/server/weapons/tracing.qc

index 1e388c4d8c6dd165a1fbdacc3ccb7d52e7ab63df..6765f598925ff769d26225708b1875af4ee57f3c 100644 (file)
@@ -45,6 +45,10 @@ float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
 int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
 bool centerprint_showing;
 
+float centerprint_medal_expire_time;
+string centerprint_medal_icon;
+float centerprint_medal_times;
+
 string centerprint_title;
 string centerprint_title_left;
 string centerprint_title_right;
@@ -151,6 +155,19 @@ void centerprint_KillAll()
        }
 }
 
+void centerprint_Medal(string icon, float times)
+{
+       if(!autocvar_hud_panel_centerprint_medals) return;
+
+       centerprint_medal_expire_time = time + MSG_MEDAL_TIME;
+       centerprint_medal_times = times;
+       if(centerprint_medal_icon)
+               strunzone(centerprint_medal_icon);
+       centerprint_medal_icon = strzone(strcat("gfx/medal/", icon));
+
+       centerprint_showing = true;
+}
+
 void centerprint_SetDuelTitle(string left, string right)
 {
        float namesize = autocvar_hud_panel_scoreboard_namesize * hud_fontsize.x;
@@ -266,6 +283,43 @@ void HUD_CenterPrint()
                pos.y += panel_size.y;
        align = bound(0, autocvar_hud_panel_centerprint_align, 1);
 
+       // Draw medals first
+       // TODO : This should be moved to a separate panel
+       if (autocvar_hud_panel_centerprint_medals && time < centerprint_medal_expire_time) {
+               float height = vid_conheight/50 * 4;
+               pos.y -= height;
+
+               if(time < centerprint_medal_expire_time - MSG_MEDAL_FADE_TIME)
+                       a = 1;
+               else
+                       a = (centerprint_medal_expire_time - time) / MSG_MEDAL_FADE_TIME;
+
+               vector tmp_in = pos;
+
+               vector mysize = draw_getimagesize(centerprint_medal_icon);
+               vector newsize = vec2(height*(mysize.x/mysize.y), height);
+               vector fontsize = '1 1 0' * (newsize.y/2);
+
+               tmp_in.x += (panel_size.x - newsize.x) / 2; // center medal icon
+
+               if(centerprint_medal_times < autocvar_hud_panel_centerprint_medals_max) {
+                       tmp_in.x -= ((newsize.x * 1.1) * (centerprint_medal_times - 1) / 2);
+                       for(int t = 0; t < centerprint_medal_times; t++) {
+                               drawpic(tmp_in, centerprint_medal_icon, newsize, '1 1 1', a, DRAWFLAG_NORMAL);
+                               tmp_in.x += newsize.x * 1.1;
+                       }
+               } else {
+                       drawpic(tmp_in, centerprint_medal_icon, newsize, '1 1 1', a, DRAWFLAG_NORMAL);
+                       tmp_in.x += newsize.x + fontsize.x * 0.25; // draw times next to it
+                       tmp_in.y += (newsize.y - fontsize.y) / 2;
+                       drawstring(tmp_in, ftos(centerprint_medal_times), fontsize, '1 1 1', a, DRAWFLAG_NORMAL);
+               }
+
+               pos.y += height;
+
+               all_messages_expired = false;
+       }
+
        // Show title if available
        if(centerprint_title != "" || centerprint_title_left != "") {
                vector fontsize = cp_fontsize * autocvar_hud_panel_centerprint_fontscale_title;
index 98f268b3456570268cde81205dc700b609d58ca2..c99a55b0af61208aea39af3557c066c8caaa2ac7 100644 (file)
@@ -18,6 +18,9 @@ float autocvar_hud_panel_centerprint_fontscale_title = 1.8;
 bool autocvar_hud_panel_centerprint_dynamichud = true;
 float autocvar_hud_panel_centerprint_time;
 
+bool autocvar_hud_panel_centerprint_medals = true;
+int autocvar_hud_panel_centerprint_medals_max = 5;
+
 void centerprint_Add(int new_id, string strMessage, float duration, int countdown_num);
 void centerprint_AddStandard(string strMessage);
 void centerprint_Kill(int id);
@@ -26,3 +29,4 @@ void centerprint_KillAll();
 void centerprint_SetDuelTitle(string left, string right);
 void centerprint_SetTitle(string title);
 void centerprint_ClearTitle();
+void centerprint_Medal(string icon, int times);
index 22087209578d1bf4d55c7fb1a0d161fe2829afd7..2f32bf89af1417ab33197adfba0d8ed883d6c5e9 100644 (file)
@@ -49,6 +49,8 @@ string autocvar_hud_fontsize;
 string hud_fontsize_str;
 float max_namesize;
 
+int total_medals;
+
 float sbt_bg_alpha;
 float sbt_fg_alpha;
 float sbt_fg_alpha_self;
@@ -1497,6 +1499,25 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
        return vec2(item_pos.x, item_pos.y + i * hud_fontsize.y * 1.25);
 }
 
+vector Scoreboard_DrawMedal(vector pos, string icon, float height, float number)
+{
+       if(!number) return pos;
+       total_medals += number;
+
+       vector tmp_sz, tmp_sz2;
+       tmp_sz = draw_getimagesize(icon);
+       tmp_sz2 = vec2(height*(tmp_sz.x/tmp_sz.y), height);
+       string val = ftos(number);
+
+       drawpic(pos, icon, tmp_sz2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       pos.x += tmp_sz2.x + hud_fontsize.x * 0.25;
+       drawstring(pos + eY * ((tmp_sz2.y - hud_fontsize.y) / 2), val, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       pos.x += stringwidth(val, false, hud_fontsize) + hud_fontsize.x * 0.5;
+       return pos;
+}
+
 vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
 {
        int max_players = 999;
@@ -1644,6 +1665,49 @@ bool Scoreboard_WouldDraw()
        return false;
 }
 
+vector Scoreboard_MedalStats_Draw(vector pos)
+{
+       vector orig = pos;
+       float height = hud_fontsize.y * 2;
+
+       entity pl = playerslots[current_player];
+
+       vector title_pos = pos;
+       pos.x += 0.5 * hud_fontsize.x + panel_bg_padding;
+       pos.y += 1.25 * hud_fontsize.y;
+
+       total_medals = 0;
+
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/airshot",            height, pl.(scores(SP_MEDAL_AIRSHOT)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/damage",             height, pl.(scores(SP_MEDAL_DAMAGE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/electrobitch",       height, pl.(scores(SP_MEDAL_ELECTROBITCH)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/excellent",          height, pl.(scores(SP_MEDAL_EXCELLENT)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/firstblood",         height, pl.(scores(SP_MEDAL_FIRSTBLOOD)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/headshot",           height, pl.(scores(SP_MEDAL_HEADSHOT)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/humiliation",        height, pl.(scores(SP_MEDAL_HUMILIATION)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/impressive",         height, pl.(scores(SP_MEDAL_IMPRESSIVE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/yoda",                       height, pl.(scores(SP_MEDAL_YODA)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/telefrag",           height, pl.(scores(SP_MEDAL_TELEFRAG)));
+
+       if(total_medals)
+               pos.x += hud_fontsize.x;
+
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/accuracy",           height, pl.(scores(SP_MEDAL_ACCURACY)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/assist",             height, pl.(scores(SP_MEDAL_ASSIST)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/capture",            height, pl.(scores(SP_MEDAL_CAPTURE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/defense",            height, pl.(scores(SP_MEDAL_DEFENSE)));
+       pos = Scoreboard_DrawMedal(pos, "gfx/medal/perfect",            height, pl.(scores(SP_MEDAL_PERFECT)));
+
+       if(!total_medals) return orig;
+
+       drawstring(title_pos, sprintf(_("Medal stats (total %d)"), total_medals),
+               hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       pos.x = orig.x;
+       pos.y += height + hud_fontsize.y * 0.5;
+       return pos;
+}
+
 float average_accuracy;
 vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
 {
@@ -2504,6 +2568,8 @@ void Scoreboard_Draw()
                pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
        }
 
+       pos = Scoreboard_MedalStats_Draw(pos);
+
        // draw scoreboard spectators before accuracy and item stats
        if (autocvar_hud_panel_scoreboard_spectators_position == 0) {
                pos = Scoreboard_Spectators_Draw(pos);
index 7a16141fc8ebbe89409b947cdfd9b979da571233..ca70fa6b3b792db788d1ed755c820e88f03a32c9 100644 (file)
@@ -44,6 +44,21 @@ void CA_count_alive_players()
 
 void nades_Clear(entity player);
 
+entity ca_LastPlayer(float tm)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, {
+               if (!IS_DEAD(it))
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
+       });
+       return last_pl;
+}
+
 int CA_PreventStalemate()
 {
        //LOG_INFO("PreventStalemate running");
@@ -140,11 +155,25 @@ float CA_CheckWinner()
        if (!winner_team)
                return 0;
 
+       bool perfect = false;
        if(winner_team > 0)
        {
+               // Defense medal: If you won the round alone
+               //entity tm = Team_GetTeam(winner_team);
+               //entity last_pl = ca_LastPlayer(winner_team);
+
+               // TODO : Get number of players in the team
+               //if(last_pl && Team_GetNumberOfPlayers(tm) >= 3) {
+               //      GIVE_MEDAL(last_pl, DEFENSE);
+               //}
+
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
                TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1);
+
+               // TODO : Get number of players in the team
+               //if (Team_GetNumberOfPlayers(tm) >= 3 && Team_GetNumberOfAlivePlayers(tm) == Team_GetNumberOfPlayers(tm))
+               //      perfect = true;
        }
        else if(winner_team == -1)
        {
@@ -161,7 +190,16 @@ float CA_CheckWinner()
        game_stopped = true;
        round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
 
-       FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               nades_Clear(it);
+
+               // Give perfect medal if everyone in the winner team is alive
+               if(perfect && it.team == winner_team) {
+                       GIVE_MEDAL(it, PERFECT);
+               }
+
+               // TODO : Accuracy medal
+       });
 
        return 1;
 }
index e16ed913829338802823dddce026e7be7f42d989..c145c1aa681ebaa8a88631644bfc02f34f8b3130 100644 (file)
@@ -614,6 +614,8 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
        if(!old_time || new_time < old_time)
                GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
 
+       GIVE_MEDAL(player, CAPTURE);
+
        // effects
        Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
 #if 0
@@ -626,8 +628,10 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
                WaypointSprite_Kill(player.wps_flagcarrier);
                if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
 
-               if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
-                       { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
+               if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper)) {
+                       GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist));
+                       GIVE_MEDAL(enemy_flag.ctf_dropper, ASSIST);
+               }
        }
 
        flag.enemy = toucher;
@@ -2250,8 +2254,26 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
 
        if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
        {
-               GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
-               GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
+               if(frag_target.flagcarried) {
+                       // Killing an enemy flag carrier
+                       GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
+                       GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
+               } else if(frag_attacker.flagcarried) {
+                       // Defense medal for killing a flag carrier
+                       GIVE_MEDAL(frag_attacker, DEFENSE);
+               } else {
+                       entity tmp_entity;
+                       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+                       if(tmp_entity.ctf_status == FLAG_BASE && CTF_SAMETEAM(tmp_entity, frag_attacker))
+                       {
+                               if(CTF_IS_NEAR(frag_target, tmp_entity, '1 1 1' * 1500))
+                               {
+                                       // Defense medal for killing an enemy near your flag
+                                       GIVE_MEDAL(frag_attacker, DEFENSE);
+                               }
+                               break;
+                       }
+               }
        }
 
        if(frag_target.flagcarried)
index adb061809fe053f56c36f763e31fb7195e0e3928..21a02f690e171b462e8d2301c307fb43629da07d 100644 (file)
@@ -176,3 +176,5 @@ void havocbot_role_ctf_setrole(entity bot, int role);
 // team checking
 #define CTF_SAMETEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
 #define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
+#define CTF_IS_NEAR(player, it, extra_size) \
+       boxesoverlap(player.absmin - extra_size, player.absmax + extra_size, it.absmin, it.absmax)
index f1e6b1ce2ec0f5b7fb3f361f9674806459d525e6..a192ed8e10f8f6b302ab08896955394c192eb14e 100644 (file)
@@ -86,6 +86,21 @@ bool freezetag_CheckTeams()
 void nades_Clear(entity);
 void nades_GiveBonus(entity player, float score);
 
+entity freezetag_LastPlayer(float tm)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, {
+               if (STAT(FROZEN, it) != FROZEN_NORMAL && GetResource(it, RES_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
+       });
+       return last_pl;
+}
+
 bool freezetag_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
@@ -108,6 +123,12 @@ bool freezetag_CheckWinner()
 
        if(winner_team > 0)
        {
+               entity last_pl = freezetag_LastPlayer(winner_team);
+               if(last_pl) {
+                       // Defense medal for winning the round alone
+                       GIVE_MEDAL(last_pl, DEFENSE);
+               }
+
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
                TeamScore_AddToTeam(winner_team, ST_FT_ROUNDS, +1);
@@ -637,6 +658,10 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
                        Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, revivers_first.netname);
                        Send_Notification(NOTIF_ONE, revivers_first, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, revivers_first.netname);
+
+                       // Assist medal for reviving a team mate
+                       GIVE_MEDAL(revivers_first, ASSIST);
+
                        if(autocvar_sv_eventlog)
                        {
                                string revivers = "";
index effed26d98f90084dd53d1afb8da23e5db5664a5..dd5a69d18380e542fabffcdf5c03cb9a5d4c2433 100644 (file)
 // MSG_ANNCE_NOTIFICATIONS
     MSG_ANNCE_NOTIF(ACHIEVEMENT_AIRSHOT,        N_GNTLOFF, "airshot",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_AMAZING,        N_GNTLOFF, "amazing",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_ASSIST,         N_GNTLOFF, "assist",            CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME,        N_GNTLOFF, "awesome",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_DAMAGE,         N_GNTLOFF, "damage",            CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_DEFENSE,        N_GNTLOFF, "defense",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_EXCELLENT,      N_GNTLOFF, "excellent",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_BOTLIKE,        N_GNTLOFF, "botlike",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_ELECTROBITCH,   N__ALWAYS, "electrobitch",      CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_IMPRESSIVE,     N_GNTLOFF, "impressive",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(ACHIEVEMENT_YODA,           N_GNTLOFF, "yoda",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_PERFECT,        N_GNTLOFF, "perfect",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_ACCURACY,       N_GNTLOFF, "accuracy",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(ACHIEVEMENT_TELEFRAG,       N_GNTLOFF, "telefrag",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(BEGIN,                      N__ALWAYS, "begin",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
 
     MSG_ANNCE_NOTIF(HEADSHOT,                   N__ALWAYS, "headshot",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(HUMILIATION,                N__ALWAYS, "humiliation",       CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(KILLSTREAK_03,              N_GNTLOFF, "03kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(KILLSTREAK_05,              N_GNTLOFF, "05kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(KILLSTREAK_10,              N_GNTLOFF, "10kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(KILLSTREAK_15,              N_GNTLOFF, "15kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(KILLSTREAK_20,              N_GNTLOFF, "20kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(KILLSTREAK_25,              N_GNTLOFF, "25kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
-    MSG_ANNCE_NOTIF(KILLSTREAK_30,              N_GNTLOFF, "30kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(INSTAGIB_LASTSECOND,        N_GNTLOFF, "lastsecond",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(INSTAGIB_NARROWLY,          N_GNTLOFF, "narrowly",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(INSTAGIB_TERMINATED,        N_GNTLOFF, "terminated",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(MULTIFRAG,                  N___NEVER, "multifrag",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
+    MSG_ANNCE_NOTIF(FIRSTBLOOD,                 N_GNTLOFF, "firstblood",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
     MSG_ANNCE_NOTIF(NUM_1,                      N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
     MSG_ANNCE_NOTIF(NUM_2,                      N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_INSTANT)
     MSG_ANNCE_NOTIF(VOTE_CALL,                  N__ALWAYS, "votecall",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
     MSG_ANNCE_NOTIF(VOTE_FAIL,                  N__ALWAYS, "votefail",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 
+// MSG_MEDAL_NOTIFICATIONS
+
+#define MSG_MEDAL_TIME 2
+#define MSG_MEDAL_FADE_TIME 0.5
+
+    MSG_MEDAL_NOTIF(AIRSHOT, N__ALWAYS,        "airshot",       ANNCE_ACHIEVEMENT_AIRSHOT)
+    MSG_MEDAL_NOTIF(ASSIST, N__ALWAYS,         "assist",        ANNCE_ACHIEVEMENT_ASSIST)
+    MSG_MEDAL_NOTIF(DAMAGE, N__ALWAYS,         "damage",        ANNCE_ACHIEVEMENT_DAMAGE)
+    MSG_MEDAL_NOTIF(DEFENSE, N__ALWAYS,        "defense",       ANNCE_ACHIEVEMENT_DEFENSE)
+    MSG_MEDAL_NOTIF(ELECTROBITCH, N__ALWAYS,   "electrobitch",  ANNCE_ACHIEVEMENT_ELECTROBITCH)
+    MSG_MEDAL_NOTIF(EXCELLENT, N__ALWAYS,      "excellent",     ANNCE_ACHIEVEMENT_EXCELLENT)
+    MSG_MEDAL_NOTIF(FIRSTBLOOD, N__ALWAYS,     "firstblood",    ANNCE_FIRSTBLOOD)
+    MSG_MEDAL_NOTIF(HEADSHOT, N__ALWAYS,       "headshot",      ANNCE_HEADSHOT)
+    MSG_MEDAL_NOTIF(HUMILIATION, N__ALWAYS,    "humiliation",   ANNCE_HUMILIATION)
+    MSG_MEDAL_NOTIF(IMPRESSIVE, N__ALWAYS,     "impressive",    ANNCE_ACHIEVEMENT_IMPRESSIVE)
+    MSG_MEDAL_NOTIF(YODA, N__ALWAYS,           "yoda",          ANNCE_ACHIEVEMENT_YODA)
+    MSG_MEDAL_NOTIF(TELEFRAG, N__ALWAYS,       "telefrag",      ANNCE_ACHIEVEMENT_TELEFRAG)
+
+    MSG_MEDAL_NOTIF(CAPTURE, N__ALWAYS,        "capture",       NULL)
+    MSG_MEDAL_NOTIF(PERFECT, N__ALWAYS,        "perfect",       ANNCE_ACHIEVEMENT_PERFECT)
+    MSG_MEDAL_NOTIF(ACCURACY, N__ALWAYS,       "accuracy",      ANNCE_ACHIEVEMENT_ACCURACY)
+
+    MSG_MEDAL_NOTIF(KILLSTREAK_03, N__ALWAYS,  "killstreak_03", ANNCE_KILLSTREAK_03)
+    MSG_MEDAL_NOTIF(KILLSTREAK_05, N__ALWAYS,  "killstreak_05", ANNCE_KILLSTREAK_05)
+    MSG_MEDAL_NOTIF(KILLSTREAK_10, N__ALWAYS,  "killstreak_10", ANNCE_KILLSTREAK_10)
+    MSG_MEDAL_NOTIF(KILLSTREAK_15, N__ALWAYS,  "killstreak_15", ANNCE_KILLSTREAK_15)
+
 #undef N___NEVER
 #undef N_GNTLOFF
 #undef N__ALWAYS
index 58910887e914a87c70393d5e0e043d6403495acb..b8a8a2e20c4cdcbfd9ec3a9cad74b9efdd6d2642 100644 (file)
@@ -419,6 +419,7 @@ void Create_Notification_Entity(entity notif,
                case MSG_CENTER:
                case MSG_MULTI:
                case MSG_CHOICE:
+               case MSG_MEDAL:
                        break;
                default:
                        LOG_INFOF(
@@ -757,6 +758,17 @@ void Create_Notification_Entity_Choice(entity notif,
                        }
                }
 
+void Create_Notification_Entity_Medal(entity notif,
+                                                                               float var_cvar,
+                                                                               string namestring,
+                                                                               /* MSG_MEDAL */
+                                                                               string icon,
+                                                                               Notification anncename)
+       {
+               notif.nent_floatcount = 1;
+               if (icon != "") { notif.nent_icon = strzone(icon); }
+               if (anncename) { notif.nent_msgannce = anncename; }
+       }
 
 // ===============
 //  Cvar Handling
@@ -829,6 +841,7 @@ void Dump_Notifications(int fh, bool alsoprint)
        int NOTIF_CENTER_COUNT = 0;
        int NOTIF_MULTI_COUNT = 0;
        int NOTIF_CHOICE_COUNT = 0;
+       int NOTIF_MEDAL_COUNT = 0;
        FOREACH(Notifications, true, {
                switch (it.nent_type)
                {
@@ -837,6 +850,7 @@ void Dump_Notifications(int fh, bool alsoprint)
                        case MSG_CENTER: ++NOTIF_CENTER_COUNT; break;
                        case MSG_MULTI: ++NOTIF_MULTI_COUNT; break;
                        case MSG_CHOICE: ++NOTIF_CHOICE_COUNT; break;
+                       case MSG_MEDAL: ++NOTIF_MEDAL_COUNT; break;
                }
        });
 
@@ -877,6 +891,13 @@ void Dump_Notifications(int fh, bool alsoprint)
                );
        });
 
+       NOTIF_WRITE(sprintf("\n// MSG_MEDAL notifications:\n"));
+       FOREACH(Notifications, it.nent_type == MSG_MEDAL && (!it.nent_teamnum || it.nent_teamnum == NUM_TEAM_1), {
+               NOTIF_WRITE_ENTITY(it,
+                       "0 = off, 1 = enabled"
+               );
+       });
+
        // edit these to match whichever cvars are used for specific notification options
        NOTIF_WRITE("\n// HARD CODED notification variables:\n");
 
@@ -965,19 +986,21 @@ void Dump_Notifications(int fh, bool alsoprint)
        );
 
        LOG_INFOF("Notification counts (total = %d): "
-               "MSG_ANNCE = %d, MSG_INFO = %d, MSG_CENTER = %d, MSG_MULTI = %d, MSG_CHOICE = %d\n",
+               "MSG_ANNCE = %d, MSG_INFO = %d, MSG_CENTER = %d, MSG_MULTI = %d, MSG_CHOICE = %d, MSG_MEDAL = %d\n",
                (
                        NOTIF_ANNCE_COUNT +
                        NOTIF_INFO_COUNT +
                        NOTIF_CENTER_COUNT +
                        NOTIF_MULTI_COUNT +
-                       NOTIF_CHOICE_COUNT
+                       NOTIF_CHOICE_COUNT +
+                       NOTIF_MEDAL_COUNT
                ),
                NOTIF_ANNCE_COUNT,
                NOTIF_INFO_COUNT,
                NOTIF_CENTER_COUNT,
                NOTIF_MULTI_COUNT,
-               NOTIF_CHOICE_COUNT
+               NOTIF_CHOICE_COUNT,
+               NOTIF_MEDAL_COUNT
        );
        #undef NOTIF_WRITE_HARDCODED
        #undef NOTIF_WRITE_ENTITY
@@ -1180,7 +1203,7 @@ void Local_Notification_centerprint_Add(
        centerprint_Add(ORDINAL(cpid), input, stof(arg_slot[0]), stof(arg_slot[1]));
 }
 
-void Local_Notification_Queue_Run(MSG net_type, entity notif)
+void Local_Notification_Queue_Run(MSG net_type, entity notif, float f1)
 {              
        switch (net_type)
        {
@@ -1189,10 +1212,22 @@ void Local_Notification_Queue_Run(MSG net_type, entity notif)
                        Local_Notification_sound(notif.nent_channel, notif.nent_snd, notif.nent_vol, notif.nent_position);
                        break;
                }
+
+               case MSG_MEDAL:
+               {
+                       centerprint_Medal(notif.nent_icon, f1);
+                       if(notif.nent_msgannce)
+                               Local_Notification_sound(
+                                       notif.nent_msgannce.nent_channel,
+                                       notif.nent_msgannce.nent_snd,
+                                       notif.nent_msgannce.nent_vol,
+                                       notif.nent_msgannce.nent_position);
+                       break;
+               }
        }
 }
 
-void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time)
+void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time, float f1)
 {      
        // Guess length if required
        if(queue_time == 0)
@@ -1200,7 +1235,7 @@ void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time)
 
        if(queue_time == -1 || time > notif_queue_next_time) {
                // Run immediately
-               Local_Notification_Queue_Run(net_type, notif);
+               Local_Notification_Queue_Run(net_type, notif, f1);
                notif_queue_next_time = time + queue_time;
        } else {
                // Put in queue
@@ -1209,6 +1244,7 @@ void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time)
                notif_queue_type[notif_queue_length] = net_type;
                notif_queue_entity[notif_queue_length] = notif;
                notif_queue_time[notif_queue_length] = notif_queue_next_time;
+               notif_queue_f1[notif_queue_length] = f1;
                
                notif_queue_next_time += queue_time;
                ++notif_queue_length;
@@ -1220,7 +1256,7 @@ void Local_Notification_Queue_Process()
        if(!notif_queue_length || notif_queue_time[0] > time)
                return;
 
-       Local_Notification_Queue_Run(notif_queue_type[0], notif_queue_entity[0]);
+       Local_Notification_Queue_Run(notif_queue_type[0], notif_queue_entity[0], notif_queue_f1[0]);
 
        // Shift queue to the left
        --notif_queue_length;
@@ -1228,6 +1264,7 @@ void Local_Notification_Queue_Process()
                notif_queue_type[j] = notif_queue_type[j+1];
                notif_queue_entity[j] = notif_queue_entity[j+1];
                notif_queue_time[j] = notif_queue_time[j+1];
+               notif_queue_f1[j] = notif_queue_f1[j+1];
        }
 }
 
@@ -1303,7 +1340,7 @@ void Local_Notification(MSG net_type, Notification net_name, ...count)
                case MSG_ANNCE:
                {
                        #ifdef CSQC
-                       Local_Notification_Queue_Add(net_type, notif, notif.nent_queuetime);
+                       Local_Notification_Queue_Add(net_type, notif, notif.nent_queuetime, f1);
                        #else
                        backtrace("MSG_ANNCE on server?... Please notify Samual immediately!\n");
                        #endif
@@ -1413,6 +1450,18 @@ void Local_Notification(MSG net_type, Notification net_name, ...count)
                                f1, f2, f3, f4);
                        break;
                }
+
+               #ifdef CSQC
+               case MSG_MEDAL:
+               {
+                       Local_Notification_Queue_Add(
+                               net_type,
+                               notif,
+                               (notif.nent_msgannce ? MSG_MEDAL_TIME : 0),
+                               f1);
+                       break;
+               }
+               #endif
        }
 }
 
index 00bd94bb740066bc03810210ece3d6238d895da8..e1c1de10cbc69e77f8abed7ce87cd94f7ed1c1f9 100644 (file)
@@ -25,6 +25,8 @@ ENUMCLASS(MSG)
        CASE(MSG, CHOICE)
        /** Kill centerprint message @deprecated */
        CASE(MSG, CENTER_KILL)
+       /** Medal notification */
+       CASE(MSG, MEDAL)
 ENUMCLASS_END(MSG)
 
 string Get_Notif_TypeName(MSG net_type)
@@ -36,6 +38,7 @@ string Get_Notif_TypeName(MSG net_type)
                case MSG_CENTER: return "MSG_CENTER";
                case MSG_MULTI: return "MSG_MULTI";
                case MSG_CHOICE: return "MSG_CHOICE";
+               case MSG_MEDAL: return "MSG_MEDAL";
                case MSG_CENTER_KILL: return "MSG_CENTER_KILL";
        }
        LOG_WARNF("Get_Notif_TypeName(%d): Improper net type!", ORDINAL(net_type));
@@ -159,6 +162,13 @@ void Create_Notification_Entity_Choice(entity notif,
                                                                                Notification optiona,
                                                                                Notification optionb);
 
+void Create_Notification_Entity_Medal(entity notif,
+                                                                               float var_cvar,
+                                                                               string namestring,
+                                                                               /* MSG_MEDAL */
+                                                                               string icon,
+                                                                               Notification anncename);
+
 void Dump_Notifications(int fh, bool alsoprint);
 
 #define DEFAULT_FILENAME "notifications_dump.cfg"
@@ -391,6 +401,7 @@ const int NOTIF_QUEUE_MAX = 10;
 entity notif_queue_entity[NOTIF_QUEUE_MAX];
 MSG notif_queue_type[NOTIF_QUEUE_MAX];
 float notif_queue_time[NOTIF_QUEUE_MAX];
+float notif_queue_f1[NOTIF_QUEUE_MAX];
 
 float notif_queue_next_time;
 int notif_queue_length;
@@ -468,9 +479,6 @@ MACRO_END
        SPREE_ITEM(5, 05, _("RAGE! "), _("%s^K1 unlocked RAGE! %s^BG"), _("%s^K1 made FIVE SCORES IN A ROW! %s^BG")) \
        SPREE_ITEM(10, 10, _("MASSACRE! "), _("%s^K1 started a MASSACRE! %s^BG"), _("%s^K1 made TEN SCORES IN A ROW! %s^BG")) \
        SPREE_ITEM(15, 15, _("MAYHEM! "), _("%s^K1 executed MAYHEM! %s^BG"), _("%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG")) \
-       SPREE_ITEM(20, 20, _("BERSERKER! "), _("%s^K1 is a BERSERKER! %s^BG"), _("%s^K1 made TWENTY SCORES IN A ROW! %s^BG")) \
-       SPREE_ITEM(25, 25, _("CARNAGE! "), _("%s^K1 inflicts CARNAGE! %s^BG"), _("%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG")) \
-       SPREE_ITEM(30, 30, _("ARMAGEDDON! "), _("%s^K1 unleashes ARMAGEDDON! %s^BG"), _("%s^K1 made THIRTY SCORES IN A ROW! %s^BG"))
 
 #ifdef CSQC
 string notif_arg_frag_ping(bool newline, float fping)
@@ -866,6 +874,18 @@ Notification Get_Notif_Ent(MSG net_type, int net_name)
                        optionb);                                /* optionb     */ \
        }
 
+#define MSG_MEDAL_NOTIF(name, defaultvalue, icon, anncename) \
+       NOTIF_ADD_AUTOCVAR(MEDAL_##name, defaultvalue) \
+       MSG_MEDAL_NOTIF_(0, MEDAL_##name, MEDAL_##name, defaultvalue, icon, anncename)
+
+#define MSG_MEDAL_NOTIF_(teamnum, name, cvarname, defaultvalue, icon, anncename) \
+       REGISTER(Notifications, name, m_id, new_pure(msg_medal_notification)) { \
+               Create_Notification_Entity      (this, defaultvalue, ACVNN(cvarname), MSG_MEDAL, strtoupper(#name), teamnum); \
+               Create_Notification_Entity_Medal(this, ACVNN(cvarname), strtoupper(#name), \
+                       icon, \
+                       anncename); \
+       }
+
 REGISTRY_BEGIN(Notifications)
 {
        notif_global_error = false;
index 8a01893f1019c423927029d57b004baa8f66b88c..fc5f418f5e6eb4c6b0c3b732bf420c93bbbea2ba 100644 (file)
@@ -91,6 +91,29 @@ REGISTER_SP(SEPARATOR);
 REGISTER_SP(KDRATIO); // kills / deaths
 REGISTER_SP(SUM); // kills - deaths
 REGISTER_SP(FRAGS); // kills - suicides
+
+// Medals
+REGISTER_SP(MEDAL_AIRSHOT);
+REGISTER_SP(MEDAL_DAMAGE);
+REGISTER_SP(MEDAL_ELECTROBITCH);
+REGISTER_SP(MEDAL_EXCELLENT);
+REGISTER_SP(MEDAL_FIRSTBLOOD);
+REGISTER_SP(MEDAL_HEADSHOT);
+REGISTER_SP(MEDAL_HUMILIATION);
+REGISTER_SP(MEDAL_IMPRESSIVE);
+REGISTER_SP(MEDAL_YODA);
+REGISTER_SP(MEDAL_TELEFRAG);
+
+REGISTER_SP(MEDAL_ACCURACY);
+REGISTER_SP(MEDAL_ASSIST);
+REGISTER_SP(MEDAL_CAPTURE);
+REGISTER_SP(MEDAL_DEFENSE);
+REGISTER_SP(MEDAL_PERFECT);
+
+REGISTER_SP(MEDAL_KILLSTREAK_03);
+REGISTER_SP(MEDAL_KILLSTREAK_05);
+REGISTER_SP(MEDAL_KILLSTREAK_10);
+REGISTER_SP(MEDAL_KILLSTREAK_15);
 #endif
 
 
index 6f428dc6c413430cb52440659da1c3a5eac6e6b5..d005e00d2cf85a60e2231a7a7314b5a25a23e58a 100644 (file)
@@ -22,8 +22,9 @@ void W_Devastator_Explode(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+                                       if(IsFlying(directhitentity)) {
+                                               GIVE_MEDAL(this.realowner, AIRSHOT);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
index 442f88265e52a0f5462079e63a96bde3fc8d27e1..1af84e6793622fbfd32d2505bf970becee72553d 100644 (file)
@@ -8,8 +8,9 @@ void W_Mortar_Grenade_Explode(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+                                       if(IsFlying(directhitentity)) {
+                                               GIVE_MEDAL(this.realowner, AIRSHOT);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
@@ -33,8 +34,9 @@ void W_Mortar_Grenade_Explode2(entity this, entity directhitentity)
                if(IS_PLAYER(directhitentity))
                        if(DIFF_TEAM(this.realowner, directhitentity))
                                if(!IS_DEAD(directhitentity))
-                                       if(IsFlying(directhitentity))
-                                               Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
+                                       if(IsFlying(directhitentity)) {
+                                               GIVE_MEDAL(this.realowner, AIRSHOT);
+                                       }
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
index 4be54b6b220378c28746b2f864cc1bc730681e46..e20fcf5c204d75c3d6028eb75df91b5e19175a79 100644 (file)
@@ -132,12 +132,17 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        SendCSQCVaporizerBeamParticle(actor, impressive_hits);
 
        if(yoda && flying)
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+       {
+               GIVE_MEDAL(actor, YODA);
+       }
+
+       /* We're going to disable Impressive medals for the vaporizer.
        if(impressive_hits && actor.vaporizer_lasthit)
        {
                Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
                impressive_hits = 0; // only every second time
        }
+       */
 
        actor.vaporizer_lasthit = impressive_hits;
 
index 4d4e43ec6cb7ea0356eb8317da2fe5833457d4e0..9cc02f25e6f9f912e48bc3fd3109debcf7efdb68 100644 (file)
@@ -130,10 +130,13 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i
        FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, false, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, dtype);
 
        if(yoda && flying)
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+       {
+               GIVE_MEDAL(actor, YODA);
+       }
+
        if(impressive_hits && actor.vortex_lasthit)
        {
-               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
+               GIVE_MEDAL(actor, IMPRESSIVE);
                impressive_hits = 0; // only every second time
        }
 
index 8c607cf9af6af6911098007d0eb5f56a41af7c32..eb5d8073f20c3fe539750e12b791ecec6767dada 100644 (file)
@@ -57,6 +57,8 @@ int autocvar_sv_spectate;
 bool autocvar_sv_teamnagger;
 float autocvar_sv_player_scale;
 
+float autocvar_g_medals_excellent_time = 2;
+
 // WEAPONTODO
 .string weaponorder_byimpulse;
 
@@ -410,3 +412,8 @@ void Join(entity this);
 #define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
 
 const int MAX_SPECTATORS = 7;
+
+float _medal_times;
+#define GIVE_MEDAL(entity,medalname) \
+       _medal_times = GameRules_scoring_add(entity, MEDAL_##medalname, 1); \
+       Send_Notification(NOTIF_ONE, entity, MSG_MEDAL, MEDAL_##medalname, _medal_times);
index 429d3e262568b56b77cab4cd76d86c73ea8de5d2..011ff4397b417126eb982606ba9eaa2bd7ab51c0 100644 (file)
@@ -169,6 +169,7 @@ void Obituary_SpecialDeath(
 
 float Obituary_WeaponDeath(
        entity notif_target,
+       entity attacker,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
@@ -201,6 +202,20 @@ float Obituary_WeaponDeath(
                        s1, s2, s3, "",
                        f1, f2, 0, 0
                );
+
+               // Special deaths for medals
+               if(attacker) {
+                       switch(death_message) {
+                               case WEAPON_SHOTGUN_MURDER_SLAP:
+                                       if(!cvar("g_melee_only")) { // don't spam humiliation if we're in melee_only mode
+                                               GIVE_MEDAL(attacker, HUMILIATION);
+                                       }
+                                       break;
+                               case WEAPON_ELECTRO_MURDER_COMBO:
+                                       GIVE_MEDAL(attacker, ELECTROBITCH);
+                                       break;
+                       }
+               }
        }
        else
        {
@@ -292,7 +307,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                                }
                        }
                }
-               else if (!Obituary_WeaponDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
+               else if (!Obituary_WeaponDeath(targ, NULL, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
                {
                        backtrace("SUICIDE: what the hell happened here?\n");
                        return;
@@ -335,7 +350,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        // these 2 macros are spread over multiple files
                        #define SPREE_ITEM(counta,countb,center,normal,gentle) \
                                case counta: \
-                                       Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
+                                       GIVE_MEDAL(attacker, KILLSTREAK_##countb); \
                                        if (!warmup_stage) \
                                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
                                        break;
@@ -351,6 +366,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        {
                                checkrules_firstblood = true;
                                notif_firstblood = true; // modify the current messages so that they too show firstblood information
+                               GIVE_MEDAL(attacker, FIRSTBLOOD);
                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
                                PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
 
@@ -364,6 +380,12 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                                kill_count_to_target = 0;
                        }
 
+                       // Excellent check
+                       if(attacker.lastkill && attacker.lastkill > time - autocvar_g_medals_excellent_time) {
+                               GIVE_MEDAL(attacker, EXCELLENT);
+                       }
+                       attacker.lastkill = time;
+
                        if(targ.istypefrag)
                        {
                                Send_Notification(
@@ -415,7 +437,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        if(deathtype == DEATH_BUFF.m_id)
                                f3 = buff_FirstFromFlags(attacker).m_id;
 
-                       if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
+                       if (!Obituary_WeaponDeath(targ, attacker, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
                                Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
                }
        }
index a1dadc1a28f052017abbcbddd6252a3c7ec3cc65..0f6055e5a5afc4c325d4c5d5211653375458b80a 100644 (file)
@@ -64,6 +64,7 @@ int impressive_hits;
 .float spawnshieldtime;
 
 .int totalfrags;
+.float lastkill;
 
 .bool canteamdamage;
 
@@ -97,6 +98,7 @@ void Obituary_SpecialDeath(
 float w_deathtype;
 float Obituary_WeaponDeath(
        entity notif_target,
+       entity attacker,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
index dbd3d5b27e6573b4d4125ff653daf3c3ff51f6e3..2c45e84cdf247d92614a7a05f19a7a8c197b5b49 100644 (file)
@@ -335,7 +335,9 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector
        IL_CLEAR(g_railgunhit);
 
        if(headshot)
-               Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT);
+       {
+               GIVE_MEDAL(this, HEADSHOT);
+       }
 
        // calculate hits and fired shots for hitscan
        if(this.(weaponentity))
@@ -490,7 +492,9 @@ void fireBullet_antilag(entity this, .entity weaponentity, vector start, vector
        }
 
        if(headshot)
-               Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT);
+       {
+               GIVE_MEDAL(this, HEADSHOT);
+       }
 
        if(lag)
                antilag_restore_all(this);