From: z411 Date: Sat, 3 Oct 2020 01:35:27 +0000 (-0300) Subject: New medals X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=4fc813cef4810718a39d5d8184b830043324b4e4;p=xonotic%2Fxonotic-data.pk3dir.git New medals --- diff --git a/qcsrc/client/hud/panel/centerprint.qc b/qcsrc/client/hud/panel/centerprint.qc index 88819c932..2948a0dec 100644 --- a/qcsrc/client/hud/panel/centerprint.qc +++ b/qcsrc/client/hud/panel/centerprint.qc @@ -45,7 +45,7 @@ bool centerprint_showing; float centerprint_medal_expire_time; string centerprint_medal_icon; -int centerprint_medal_times; +float centerprint_medal_times; bool centerprint_title_show; string centerprint_title; @@ -65,7 +65,7 @@ void centerprint_SetTitle(string title) } } -void centerprint_Medal(string icon, int times) +void centerprint_Medal(string icon, float times) { LOG_INFOF("centerprint_Medal: icon: %s times: %d", icon, times); @@ -274,19 +274,32 @@ void HUD_CenterPrint() pos.y -= height; // z411 draw medals first - if (centerprint_medal_expire_time > time) { - //if(centerprint_medal_expire_time - time > 1) - // a = 1; - //else - // a = min(1, 1 - ((centerprint_medal_expire_time - time + 2) * (1/3))); + if (time < centerprint_medal_expire_time) { + if(time < centerprint_medal_expire_time - 1) + a = 1; + else + a = centerprint_medal_expire_time - time; + + vector tmp_in = pos; mysize = draw_getimagesize(centerprint_medal_icon); newsize = vec2(height*(mysize.x/mysize.y), height); + fontsize = '1 1 0' * (newsize.y/2); - //fontsize = '1 1 0' * vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale; - //drawcolorcodedstring(pos + eY * 0.5 * (1 - sz * hud_scale.x) * fontsize.y, ts, fontsize, 1, DRAWFLAG_NORMAL); - //drawstring(pos, centerprint_medal_icon, fontsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawpic(pos + eX * 0.5 * panel_size.x - eX * (newsize.x / 2), centerprint_medal_icon, newsize, '1 1 1', 1, DRAWFLAG_NORMAL); + tmp_in.x += (panel_size.x - newsize.x) / 2; // center medal icon + + if(centerprint_medal_times <= 5) { + 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); + } all_messages_expired = false; } diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc index 0cea8df91..0fcb5c560 100644 --- a/qcsrc/client/hud/panel/scoreboard.qc +++ b/qcsrc/client/hud/panel/scoreboard.qc @@ -49,6 +49,7 @@ float max_namesize; vector duel_score_fontsize; vector duel_name_fontsize; vector duel_score_size; +int total_medals; float sbt_bg_alpha; float sbt_fg_alpha; @@ -1055,6 +1056,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_Duel_DrawPickup(vector pos, bool skinned, string icon, vector sz, float number, bool invert) { vector tmp_in = pos; @@ -1082,7 +1102,7 @@ vector Scoreboard_Duel_DrawPickup(vector pos, bool skinned, string icon, vector else tmp_in.x -= hud_fontsize.x * 0.25 + hud_fontsize.x; tmp_in.y += (tmp_sz2.y - hud_fontsize.y) / 2; - drawstring(tmp_in, ftos(number), hud_fontsize, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring(tmp_in, ftos(number), hud_fontsize, (number ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL); pos.y += sz.y * 1.1; return pos; @@ -1211,19 +1231,19 @@ void Scoreboard_Duel_DrawTable(vector pos, bool invert, entity pl, entity tm) draw_str = ftos(pl.accuracy_frags[i - WEP_FIRST]); drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2), - draw_str, hud_fontsize, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL); + draw_str, hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL); draw_str = ftos(pl.accuracy_hit[i - WEP_FIRST]); drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2), - draw_str, hud_fontsize, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL); + draw_str, hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL); draw_str = sprintf("%d%%", weapon_acc); drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2), - draw_str, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + draw_str, hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL); draw_str = strcat(ftos(weapon_cnt_hit), " / ", ftos(weapon_cnt_fired)); drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * (column_width / 2) - eX * stringwidth("36 /", false, hud_fontsize), - draw_str,hud_fontsize, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL); + draw_str,hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL); // weapon icon if(invert) { @@ -1254,9 +1274,9 @@ void Scoreboard_Duel_DrawTable(vector pos, bool invert, entity pl, entity tm) "medals", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL); tmp.y += hud_fontsize.y * 1.25; - tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/yoda", icon_sz, 0, invert); - tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/airshot", icon_sz, 0, invert); - tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/firstblood", icon_sz, 0, invert); + tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/humiliation", icon_sz, pl.(scores(SP_MEDAL_HUMILIATION)), invert); + tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/impressive", icon_sz, pl.(scores(SP_MEDAL_IMPRESSIVE)), invert); + tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/excellent", icon_sz, pl.(scores(SP_MEDAL_EXCELLENT)), invert); // Item rows drawstring(tmp + eX * ((column_width - stringwidth("items", false, hud_fontsize)) / 2), @@ -1279,29 +1299,8 @@ vector Scoreboard_MakeDuelTable(vector pos, entity tm, vector rgb, vector bg_siz float screen_half = panel_size.x / 2; float weapon_margin = hud_fontsize.x; - // Get weapon count - WepSet weapons_inmap = WepSet_GetFromStat_InMap(); - int disownedcnt = 0; - int nHidden = 0; - FOREACH(Weapons, it != WEP_Null, { - WepSet set = it.m_wepset; - if(it.spawnflags & WEP_TYPE_OTHER) - { - ++nHidden; - continue; - } - if (!(weapons_inmap & set)) - { - if (it.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)) - ++nHidden; - else - ++disownedcnt; - } - }); - - int weapon_cnt = (REGISTRY_COUNT(Weapons) - 1) - disownedcnt - nHidden; panel_size.x = screen_half - weapon_margin; - panel_size.y = (duel_score_size.y * 3) + (hud_fontsize.y * 1.25 * weapon_cnt); + panel_size.y = (duel_score_size.y * 5.5); entity pl_left = players.sort_next; entity pl_right = pl_left.sort_next; @@ -1429,6 +1428,41 @@ 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/assist", height, pl.(scores(SP_MEDAL_ASSIST))); + pos = Scoreboard_DrawMedal(pos, "gfx/medal/damage", height, pl.(scores(SP_MEDAL_DAMAGE))); + pos = Scoreboard_DrawMedal(pos, "gfx/medal/defense", height, pl.(scores(SP_MEDAL_DEFENSE))); + 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))); + + 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) { @@ -2114,6 +2148,8 @@ void Scoreboard_Draw() pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size); } + pos = Scoreboard_MedalStats_Draw(pos); + if (Scoreboard_AccuracyStats_WouldDraw(pos.y)) pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size); diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index fdd3a34eb..dd01090f3 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -622,7 +622,7 @@ NET_HANDLE(ENT_CLIENT_ACCURACY, bool isnew) playerslots[entnum-1].accuracy_cnt_hit[w] = ReadShort(); playerslots[entnum-1].accuracy_cnt_fired[w] = ReadShort(); - LOG_INFOF("Duel stats ?/%d", playerslots[entnum-1].accuracy_cnt_fired[w]); + //LOG_INFOF("Duel stats ?/%d", playerslots[entnum-1].accuracy_cnt_fired[w]); } else { int b = ReadByte(); if (b == 0) diff --git a/qcsrc/common/medals.qh b/qcsrc/common/medals.qh new file mode 100644 index 000000000..b12581bb0 --- /dev/null +++ b/qcsrc/common/medals.qh @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + +REGISTRY(Medals, 32) +REGISTER_REGISTRY(Medals) +#define REGISTER_MEDAL(id, class) REGISTER(Medals, MEDAL, id, m_id, NEW(class)) + +REGISTRY_SORT(Medals) +REGISTRY_CHECK(Medals) + +REGISTRY_DEFINE_GET(Medals, NULL) +STATIC_INIT(Medals) { FOREACH(Medals, true, it.m_id = i); } + +CLASS(Medal, Object) +ENDCLASS(Medal) + +REGISTER_MEDAL(Airshot, Medal) { + this.netname = "airshot"; + this.m_name = _("Airshot"); + this.m_icon = "airshot"; + this.m_annce = ANNCE_ACHIEVEMENT_IMPRESSIVE; +} + +REGISTER_MEDAL(Impressive, Medal) { + this.netname = "impressive"; + this.m_name = _("Impressive"); + this.m_icon = "impressive"; + //this.m_annce = ANNCE_ACHIEVEMENT_IMPRESSIVE; +} + diff --git a/qcsrc/common/medals/all.qh b/qcsrc/common/medals/all.qh new file mode 100644 index 000000000..bfbc6104a --- /dev/null +++ b/qcsrc/common/medals/all.qh @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "medal.qh" + +// NOTE: 24 is the limit for the .items field +REGISTRY(Medals, 32) +REGISTER_REGISTRY(Medals) +#define REGISTER_MEDAL(id, class) REGISTER(Medals, MEDAL, id, m_id, NEW(class)) + +REGISTRY_SORT(Medals) +REGISTRY_CHECK(Medals) + +REGISTRY_DEFINE_GET(Medals, NULL) +STATIC_INIT(Medals) { FOREACH(Medals, true, it.m_id = i); } + +CLASS(Medal) +ENDCLASS(Medal) + +REGISTER_ITEM(Impressive, Medal) { +#ifdef GAMEQC + this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE; + this.m_model = MDL_HealthSmall_ITEM; + this.m_sound = SND_HealthSmall; +#endif + this.netname = "impressive"; + this.m_name = _("Impressive"); + this.m_icon = "impressive"; +#ifdef SVQC + this.annce = ANNCE_ACHIEVEMENT_IMPRESSIVE; +#endif +} diff --git a/qcsrc/common/mutators/mutator/overkill/oknex.qc b/qcsrc/common/mutators/mutator/overkill/oknex.qc index e5e0b7e84..bba6db11d 100644 --- a/qcsrc/common/mutators/mutator/overkill/oknex.qc +++ b/qcsrc/common/mutators/mutator/overkill/oknex.qc @@ -97,12 +97,13 @@ void W_OverkillNex_Attack(Weapon thiswep, entity actor, .entity weaponentity, fl damage_goodhits = 0; FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, true, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, thiswep.m_id); - if(yoda && flying) - Send_Notification(NOTIF_ONE, actor, MSG_MEDAL, MEDAL_YODA); + if(yoda && flying) { + Give_Medal(actor, YODA); + } + if(damage_goodhits && actor.oknex_lasthit) { - //Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE); - Send_Notification(NOTIF_ONE, actor, MSG_MEDAL, MEDAL_IMPRESSIVE); + Give_Medal(actor, IMPRESSIVE); damage_goodhits = 0; // only every second time } diff --git a/qcsrc/common/notifications/all.inc b/qcsrc/common/notifications/all.inc index 930c6d21b..f421867f8 100644 --- a/qcsrc/common/notifications/all.inc +++ b/qcsrc/common/notifications/all.inc @@ -103,7 +103,11 @@ // MSG_ANNCE_NOTIFICATIONS MSG_ANNCE_NOTIF(ACHIEVEMENT_AIRSHOT, N_GNTLOFF, "airshot", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(ACHIEVEMENT_AMAZING, N_GNTLOFF, "amazing", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) - MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME, N_GNTLOFF, "awesome", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) + MSG_ANNCE_NOTIF(ACHIEVEMENT_ASSIST, N_GNTLOFF, "assist", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) + MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME, N_GNTLOFF, "awesome", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) + MSG_ANNCE_NOTIF(ACHIEVEMENT_DAMAGE, N_GNTLOFF, "damage", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) + MSG_ANNCE_NOTIF(ACHIEVEMENT_DEFENSE, N_GNTLOFF, "defense", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) + MSG_ANNCE_NOTIF(ACHIEVEMENT_EXCELLENT, N_GNTLOFF, "excellent", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(ACHIEVEMENT_BOTLIKE, N_GNTLOFF, "botlike", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(ACHIEVEMENT_ELECTROBITCH, N__ALWAYS, "electrobitch", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(ACHIEVEMENT_IMPRESSIVE, N_GNTLOFF, "impressive", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) @@ -112,14 +116,12 @@ MSG_ANNCE_NOTIF(BEGIN, N__ALWAYS, "begin", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(HEADSHOT, N__ALWAYS, "headshot", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) + MSG_ANNCE_NOTIF(HUMILIATION, N__ALWAYS, "humiliation", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(KILLSTREAK_03, N_GNTLOFF, "03kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(KILLSTREAK_05, N_GNTLOFF, "05kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(KILLSTREAK_10, N_GNTLOFF, "10kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(KILLSTREAK_15, N_GNTLOFF, "15kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) - MSG_ANNCE_NOTIF(KILLSTREAK_20, N_GNTLOFF, "20kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) - MSG_ANNCE_NOTIF(KILLSTREAK_25, N_GNTLOFF, "25kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) - MSG_ANNCE_NOTIF(KILLSTREAK_30, N_GNTLOFF, "30kills", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(INSTAGIB_LASTSECOND, N_GNTLOFF, "lastsecond", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) MSG_ANNCE_NOTIF(INSTAGIB_NARROWLY, N_GNTLOFF, "narrowly", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) @@ -231,20 +233,22 @@ MSG_ANNCE_NOTIF(ALONE, N__ALWAYS, "alone", CH_INFO, VOL_BASEVOICE, ATTEN_NONE) // MSG_MEDAL_NOTIFICATIONS - MSG_MEDAL_NOTIF(AIRSHOT, N__ALWAYS, "airshot", ANNCE_ACHIEVEMENT_AIRSHOT) - MSG_MEDAL_NOTIF(HEADSHOT, N__ALWAYS, "headshot", ANNCE_HEADSHOT) - MSG_MEDAL_NOTIF(IMPRESSIVE, N__ALWAYS, "impressive", ANNCE_ACHIEVEMENT_IMPRESSIVE) - MSG_MEDAL_NOTIF(YODA, N__ALWAYS, "yoda", ANNCE_ACHIEVEMENT_YODA) + 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(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) - MSG_MEDAL_NOTIF(KILLSTREAK_20, N__ALWAYS, "killstreak_20", ANNCE_KILLSTREAK_20) - MSG_MEDAL_NOTIF(KILLSTREAK_25, N__ALWAYS, "killstreak_25", ANNCE_KILLSTREAK_25) - MSG_MEDAL_NOTIF(KILLSTREAK_30, N__ALWAYS, "killstreak_30", ANNCE_KILLSTREAK_30) - - MSG_MEDAL_NOTIF(FIRSTBLOOD, N__ALWAYS, "firstblood", ANNCE_FIRSTBLOOD) #undef N___NEVER diff --git a/qcsrc/common/notifications/all.qc b/qcsrc/common/notifications/all.qc index 503c67c03..972b0d092 100644 --- a/qcsrc/common/notifications/all.qc +++ b/qcsrc/common/notifications/all.qc @@ -759,6 +759,7 @@ void Create_Notification_Entity_Medal(entity notif, string icon, Notification anncename) { + notif.nent_floatcount = 1; if (icon != "") { notif.nent_icon = strzone(icon); } if (anncename) { notif.nent_msgannce = anncename; } } @@ -1199,7 +1200,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) { @@ -1211,14 +1212,14 @@ void Local_Notification_Queue_Run(MSG net_type, entity notif) case MSG_MEDAL: { - centerprint_Medal(notif.nent_icon, 1); + centerprint_Medal(notif.nent_icon, f1); 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) { if(notif_queue_length >= NOTIF_QUEUE_MAX) return; @@ -1227,13 +1228,14 @@ void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time) if(time > notif_queue_next_time) { //LOG_INFOF("Running NOW!"); - Local_Notification_Queue_Run(net_type, notif); + Local_Notification_Queue_Run(net_type, notif, f1); notif_queue_next_time = time + queue_time; } else { //LOG_INFOF("Queueing: %d %d", notif_queue_length, notif_queue_next_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; @@ -1249,13 +1251,14 @@ void Local_Notification_Queue_Process() if(notif_queue_time[0] <= time) { //LOG_INFOF("Process running: %d <= %d", notif_queue_time[0], time); - 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 for (j = 0; j < notif_queue_length - 1; j++) { 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]; } --notif_queue_length; @@ -1335,7 +1338,11 @@ void Local_Notification(MSG net_type, Notification net_name, ...count) { #ifdef CSQC //Local_Notification_sound(notif.nent_channel, notif.nent_snd, notif.nent_vol, notif.nent_position); - Local_Notification_Queue_Add(net_type, notif, 1); + Local_Notification_Queue_Add( + net_type, + notif, + 1, + f1); #else backtrace("MSG_ANNCE on server?... Please notify Samual immediately!\n"); #endif @@ -1449,7 +1456,11 @@ void Local_Notification(MSG net_type, Notification net_name, ...count) #ifdef CSQC case MSG_MEDAL: { - Local_Notification_Queue_Add(net_type, notif, 3); + Local_Notification_Queue_Add( + net_type, + notif, + 3, + f1); break; } #endif diff --git a/qcsrc/common/notifications/all.qh b/qcsrc/common/notifications/all.qh index 2b39c17ba..af4b0dc44 100644 --- a/qcsrc/common/notifications/all.qh +++ b/qcsrc/common/notifications/all.qh @@ -402,6 +402,8 @@ 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; @@ -478,9 +480,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) diff --git a/qcsrc/common/scores.qh b/qcsrc/common/scores.qh index 3bc6c5563..ee762ff24 100644 --- a/qcsrc/common/scores.qh +++ b/qcsrc/common/scores.qh @@ -1,6 +1,6 @@ #pragma once -#define MAX_SCORE 64 +#define MAX_SCORE 128 #define REGISTER_SP(id) REGISTER(Scores, SP, id, m_id, new_pure(PlayerScoreField)) REGISTRY(Scores, MAX_SCORE); @@ -85,6 +85,23 @@ REGISTER_SP(NEXBALL_FAULTS); REGISTER_SP(ONS_TAKES); REGISTER_SP(ONS_CAPS); + +REGISTER_SP(MEDAL_AIRSHOT); +REGISTER_SP(MEDAL_ASSIST); +REGISTER_SP(MEDAL_DAMAGE); +REGISTER_SP(MEDAL_DEFENSE); +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_KILLSTREAK_03); +REGISTER_SP(MEDAL_KILLSTREAK_05); +REGISTER_SP(MEDAL_KILLSTREAK_10); +REGISTER_SP(MEDAL_KILLSTREAK_15); #endif diff --git a/qcsrc/common/weapons/weapon/devastator.qc b/qcsrc/common/weapons/weapon/devastator.qc index 9ed008c99..ce60f0907 100644 --- a/qcsrc/common/weapons/weapon/devastator.qc +++ b/qcsrc/common/weapons/weapon/devastator.qc @@ -23,8 +23,7 @@ void W_Devastator_Explode(entity this, entity 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); - Send_Notification(NOTIF_ONE, this.realowner, MSG_MEDAL, MEDAL_AIRSHOT); + Give_Medal(this.realowner, AIRSHOT); } this.event_damage = func_null; diff --git a/qcsrc/common/weapons/weapon/electro.qc b/qcsrc/common/weapons/weapon/electro.qc index 10005f22e..4fc98e843 100644 --- a/qcsrc/common/weapons/weapon/electro.qc +++ b/qcsrc/common/weapons/weapon/electro.qc @@ -78,8 +78,9 @@ void W_Electro_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_ELECTROBITCH); + if(IsFlying(directhitentity)) { + Give_Medal(this.realowner, ELECTROBITCH); + } this.event_damage = func_null; this.takedamage = DAMAGE_NO; diff --git a/qcsrc/common/weapons/weapon/mortar.qc b/qcsrc/common/weapons/weapon/mortar.qc index 1f72cebbb..f42377191 100644 --- a/qcsrc/common/weapons/weapon/mortar.qc +++ b/qcsrc/common/weapons/weapon/mortar.qc @@ -9,8 +9,7 @@ void W_Mortar_Grenade_Explode(entity this, entity 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); - Send_Notification(NOTIF_ONE, this.realowner, MSG_MEDAL, MEDAL_AIRSHOT); + Give_Medal(this.realowner, AIRSHOT); } this.event_damage = func_null; @@ -36,8 +35,7 @@ void W_Mortar_Grenade_Explode2(entity this, entity 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); - Send_Notification(NOTIF_ONE, this.realowner, MSG_MEDAL, MEDAL_AIRSHOT); + Give_Medal(this.realowner, AIRSHOT); } this.event_damage = func_null; diff --git a/qcsrc/common/weapons/weapon/vaporizer.qc b/qcsrc/common/weapons/weapon/vaporizer.qc index 2d5ef26d1..669894bdc 100644 --- a/qcsrc/common/weapons/weapon/vaporizer.qc +++ b/qcsrc/common/weapons/weapon/vaporizer.qc @@ -131,11 +131,13 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity) W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, normalize(v - w_shotorg)); SendCSQCVaporizerBeamParticle(actor, damage_goodhits); - if(yoda && flying) - Send_Notification(NOTIF_ONE, actor, MSG_MEDAL, MEDAL_YODA); + if(yoda && flying) { + Give_Medal(actor, YODA); + } + if(damage_goodhits && actor.vaporizer_lasthit) { - Send_Notification(NOTIF_ONE, actor, MSG_MEDAL, MEDAL_IMPRESSIVE); + Give_Medal(actor, IMPRESSIVE); damage_goodhits = 0; // only every second time } @@ -154,8 +156,9 @@ void W_RocketMinsta_Laser_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_ELECTROBITCH); + if(IsFlying(directhitentity)) { + Give_Medal(this.realowner, ELECTROBITCH); + } this.event_damage = func_null; this.takedamage = DAMAGE_NO; diff --git a/qcsrc/common/weapons/weapon/vortex.qc b/qcsrc/common/weapons/weapon/vortex.qc index 55b4d56f1..99a02720f 100644 --- a/qcsrc/common/weapons/weapon/vortex.qc +++ b/qcsrc/common/weapons/weapon/vortex.qc @@ -141,12 +141,13 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i damage_goodhits = 0; 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_MEDAL, MEDAL_YODA); + if(yoda && flying) { + Give_Medal(actor, YODA); + } + if(damage_goodhits && actor.vortex_lasthit) { - //Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE); - Send_Notification(NOTIF_ONE, actor, MSG_MEDAL, MEDAL_IMPRESSIVE); + Give_Medal(actor, IMPRESSIVE); damage_goodhits = 0; // only every second time } diff --git a/qcsrc/server/client.qh b/qcsrc/server/client.qh index 23c4a38f4..b7b346e68 100644 --- a/qcsrc/server/client.qh +++ b/qcsrc/server/client.qh @@ -263,6 +263,7 @@ bool independent_players; #define IS_INDEPENDENT_PLAYER(e) ((e).solid == SOLID_TRIGGER) #define MAKE_INDEPENDENT_PLAYER(e) (((e).solid = SOLID_TRIGGER), ((e).frags = FRAGS_PLAYER_OUT_OF_GAME)) +.float lastkill; .int killcount; //flood fields @@ -399,6 +400,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc const int MAX_SPECTATORS = 7; -#define GIVE_MEDAL(entity,medalname) \ - Send_Notification(NOTIF_ONE, entity, MSG_ANNCE, ANNCE_ACHIEVEMENT_##medalname); \ - Send_Notification(NOTIF_ONE, entity, MSG_MEDAL, MEDAL_##medalname); +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); diff --git a/qcsrc/server/damage.qc b/qcsrc/server/damage.qc index 06ec577e4..bbb82110e 100644 --- a/qcsrc/server/damage.qc +++ b/qcsrc/server/damage.qc @@ -334,7 +334,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_MEDAL, MEDAL_KILLSTREAK_##countb); \ + Give_Medal(attacker, KILLSTREAK_##countb); \ if (!warmup_stage) \ PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \ break; @@ -350,7 +350,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 - Send_Notification(NOTIF_ONE, attacker, MSG_MEDAL, MEDAL_FIRSTBLOOD); + Give_Medal(attacker, FIRSTBLOOD); PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1); PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1); @@ -363,6 +363,12 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en kill_count_to_attacker = CS(attacker).killcount; kill_count_to_target = 0; } + + // Excellent check + if(attacker.lastkill && attacker.lastkill > time - 2) { + Give_Medal(attacker, EXCELLENT); + } + attacker.lastkill = time; if(targ.istypefrag) { diff --git a/qcsrc/server/damage.qh b/qcsrc/server/damage.qh index 02a637ca0..27473a24c 100644 --- a/qcsrc/server/damage.qh +++ b/qcsrc/server/damage.qh @@ -63,6 +63,7 @@ float damage_gooddamage; .float spawnshieldtime; .int totalfrags; +.float lastkill; .bool canteamdamage; diff --git a/qcsrc/server/scores.qc b/qcsrc/server/scores.qc index c375d397e..99b55083b 100644 --- a/qcsrc/server/scores.qc +++ b/qcsrc/server/scores.qc @@ -276,8 +276,8 @@ float PlayerScore_Clear(entity player) sk = CS(player).scorekeeper; FOREACH(Scores, true, { if(sk.(scores(it)) != 0) - if(scores_label(it) != "") - sk.SendFlags |= (2 ** (i % 16)); + //if(scores_label(it) != "") + sk.SendFlags |= (2 ** (i % 16)); if(i != SP_ELO.m_id) sk.(scores(it)) = 0; }); @@ -294,8 +294,8 @@ void Score_ClearAll() if (!sk) continue; FOREACH(Scores, true, { if(sk.(scores(it)) != 0) - if(scores_label(it) != "") - sk.SendFlags |= (2 ** (i % 16)); + //if(scores_label(it) != "") + sk.SendFlags |= (2 ** (i % 16)); if(i != SP_ELO.m_id) sk.(scores(it)) = 0; }); @@ -308,8 +308,8 @@ void Score_ClearAll() for(int j = 0; j < MAX_TEAMSCORE; ++j) { if(sk.(teamscores(j)) != 0) - if(teamscores_label(j) != "") - sk.SendFlags |= (2 ** j); + //if(teamscores_label(j) != "") + sk.SendFlags |= (2 ** j); sk.(teamscores(j)) = 0; } } @@ -356,8 +356,8 @@ float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score) { return s.(scores(scorefield)); } - if(scores_label(scorefield) != "") - s.SendFlags |= (2 ** (scorefield.m_id % 16)); + //if(scores_label(scorefield) != "") + s.SendFlags |= (2 ** (scorefield.m_id % 16)); if(!warmup_stage) PlayerStats_GameReport_Event_Player(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score); s.(scores(scorefield)) += score; diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index f4de0e1bf..7c9bfb433 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -329,8 +329,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); + if(headshot) { + Give_Medal(this, HEADSHOT); + } // calculate hits and fired shots for hitscan if(this.(weaponentity)) @@ -484,8 +485,9 @@ void fireBullet_antilag(entity this, .entity weaponentity, vector start, vector Damage_DamageInfo(start, 0, 0, 0, max(1, force) * normalize(dir) * -damage_fraction, dtype, 0, this); } - if(headshot) - Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT); + if(headshot) { + Give_Medal(this, HEADSHOT); + } if(lag) antilag_restore_all(this);