diff --git a/assets/japro/hud/mod/DEMP2.png b/assets/japro/hud/mod/DEMP2.png
new file mode 100644
index 0000000000..b9574948ea
Binary files /dev/null and b/assets/japro/hud/mod/DEMP2.png differ
diff --git a/assets/japro/hud/mod/DEMP2_alt.png b/assets/japro/hud/mod/DEMP2_alt.png
new file mode 100644
index 0000000000..78b9ca72e9
Binary files /dev/null and b/assets/japro/hud/mod/DEMP2_alt.png differ
diff --git a/assets/japro/hud/mod/bowcaster.png b/assets/japro/hud/mod/bowcaster.png
new file mode 100644
index 0000000000..973314bb00
Binary files /dev/null and b/assets/japro/hud/mod/bowcaster.png differ
diff --git a/assets/japro/hud/mod/concussion.png b/assets/japro/hud/mod/concussion.png
new file mode 100644
index 0000000000..9002684046
Binary files /dev/null and b/assets/japro/hud/mod/concussion.png differ
diff --git a/assets/japro/hud/mod/concussion_alt.png b/assets/japro/hud/mod/concussion_alt.png
new file mode 100644
index 0000000000..f4518758ef
Binary files /dev/null and b/assets/japro/hud/mod/concussion_alt.png differ
diff --git a/assets/japro/hud/mod/crushed.png b/assets/japro/hud/mod/crushed.png
new file mode 100644
index 0000000000..284bec96aa
Binary files /dev/null and b/assets/japro/hud/mod/crushed.png differ
diff --git a/assets/japro/hud/mod/detpack.png b/assets/japro/hud/mod/detpack.png
new file mode 100644
index 0000000000..42396aef68
Binary files /dev/null and b/assets/japro/hud/mod/detpack.png differ
diff --git a/assets/japro/hud/mod/disruptor.png b/assets/japro/hud/mod/disruptor.png
new file mode 100644
index 0000000000..58ee7acc90
Binary files /dev/null and b/assets/japro/hud/mod/disruptor.png differ
diff --git a/assets/japro/hud/mod/disruptor_alt.png b/assets/japro/hud/mod/disruptor_alt.png
new file mode 100644
index 0000000000..2c52c8d524
Binary files /dev/null and b/assets/japro/hud/mod/disruptor_alt.png differ
diff --git a/assets/japro/hud/mod/fall.png b/assets/japro/hud/mod/fall.png
new file mode 100644
index 0000000000..966b86933b
Binary files /dev/null and b/assets/japro/hud/mod/fall.png differ
diff --git a/assets/japro/hud/mod/flachette.png b/assets/japro/hud/mod/flachette.png
new file mode 100644
index 0000000000..f94e69e6f1
Binary files /dev/null and b/assets/japro/hud/mod/flachette.png differ
diff --git a/assets/japro/hud/mod/flachette_alt.png b/assets/japro/hud/mod/flachette_alt.png
new file mode 100644
index 0000000000..6b4300d244
Binary files /dev/null and b/assets/japro/hud/mod/flachette_alt.png differ
diff --git a/assets/japro/hud/mod/force.png b/assets/japro/hud/mod/force.png
new file mode 100644
index 0000000000..c2679ee113
Binary files /dev/null and b/assets/japro/hud/mod/force.png differ
diff --git a/assets/japro/hud/mod/generic.png b/assets/japro/hud/mod/generic.png
new file mode 100644
index 0000000000..943e37f57a
Binary files /dev/null and b/assets/japro/hud/mod/generic.png differ
diff --git a/assets/japro/hud/mod/lava.png b/assets/japro/hud/mod/lava.png
new file mode 100644
index 0000000000..96f2c61fff
Binary files /dev/null and b/assets/japro/hud/mod/lava.png differ
diff --git a/assets/japro/hud/mod/melee.png b/assets/japro/hud/mod/melee.png
new file mode 100644
index 0000000000..3490fcd27d
Binary files /dev/null and b/assets/japro/hud/mod/melee.png differ
diff --git a/assets/japro/hud/mod/merrsonn.png b/assets/japro/hud/mod/merrsonn.png
new file mode 100644
index 0000000000..145314d3f9
Binary files /dev/null and b/assets/japro/hud/mod/merrsonn.png differ
diff --git a/assets/japro/hud/mod/merrsonn_alt.png b/assets/japro/hud/mod/merrsonn_alt.png
new file mode 100644
index 0000000000..e1a1659b98
Binary files /dev/null and b/assets/japro/hud/mod/merrsonn_alt.png differ
diff --git a/assets/japro/hud/mod/merrsonn_splash.png b/assets/japro/hud/mod/merrsonn_splash.png
new file mode 100644
index 0000000000..ce3387fe0d
Binary files /dev/null and b/assets/japro/hud/mod/merrsonn_splash.png differ
diff --git a/assets/japro/hud/mod/mine.png b/assets/japro/hud/mod/mine.png
new file mode 100644
index 0000000000..4144e17b44
Binary files /dev/null and b/assets/japro/hud/mod/mine.png differ
diff --git a/assets/japro/hud/mod/mine_alt.png b/assets/japro/hud/mod/mine_alt.png
new file mode 100644
index 0000000000..889343c6ad
Binary files /dev/null and b/assets/japro/hud/mod/mine_alt.png differ
diff --git a/assets/japro/hud/mod/ooze.png b/assets/japro/hud/mod/ooze.png
new file mode 100644
index 0000000000..5d504265c5
Binary files /dev/null and b/assets/japro/hud/mod/ooze.png differ
diff --git a/assets/japro/hud/mod/pistol.png b/assets/japro/hud/mod/pistol.png
new file mode 100644
index 0000000000..3d61f2a488
Binary files /dev/null and b/assets/japro/hud/mod/pistol.png differ
diff --git a/assets/japro/hud/mod/pistol_alt.png b/assets/japro/hud/mod/pistol_alt.png
new file mode 100644
index 0000000000..cfb8b2bfe7
Binary files /dev/null and b/assets/japro/hud/mod/pistol_alt.png differ
diff --git a/assets/japro/hud/mod/portable_turret.png b/assets/japro/hud/mod/portable_turret.png
new file mode 100644
index 0000000000..add50401b2
Binary files /dev/null and b/assets/japro/hud/mod/portable_turret.png differ
diff --git a/assets/japro/hud/mod/repeater.png b/assets/japro/hud/mod/repeater.png
new file mode 100644
index 0000000000..e1bc853177
Binary files /dev/null and b/assets/japro/hud/mod/repeater.png differ
diff --git a/assets/japro/hud/mod/repeater_alt.png b/assets/japro/hud/mod/repeater_alt.png
new file mode 100644
index 0000000000..462f7e9584
Binary files /dev/null and b/assets/japro/hud/mod/repeater_alt.png differ
diff --git a/assets/japro/hud/mod/rifle.png b/assets/japro/hud/mod/rifle.png
new file mode 100644
index 0000000000..66b3b9f733
Binary files /dev/null and b/assets/japro/hud/mod/rifle.png differ
diff --git a/assets/japro/hud/mod/rifle_alt.png b/assets/japro/hud/mod/rifle_alt.png
new file mode 100644
index 0000000000..feca10fd8d
Binary files /dev/null and b/assets/japro/hud/mod/rifle_alt.png differ
diff --git a/assets/japro/hud/mod/saber.png b/assets/japro/hud/mod/saber.png
new file mode 100644
index 0000000000..bf3e7ebbad
Binary files /dev/null and b/assets/japro/hud/mod/saber.png differ
diff --git a/assets/japro/hud/mod/stun.png b/assets/japro/hud/mod/stun.png
new file mode 100644
index 0000000000..a9c858e5ff
Binary files /dev/null and b/assets/japro/hud/mod/stun.png differ
diff --git a/assets/japro/hud/mod/swoop.png b/assets/japro/hud/mod/swoop.png
new file mode 100644
index 0000000000..451020a5db
Binary files /dev/null and b/assets/japro/hud/mod/swoop.png differ
diff --git a/assets/japro/hud/mod/telefrag.png b/assets/japro/hud/mod/telefrag.png
new file mode 100644
index 0000000000..c76e252a1b
Binary files /dev/null and b/assets/japro/hud/mod/telefrag.png differ
diff --git a/assets/japro/hud/mod/thermal.png b/assets/japro/hud/mod/thermal.png
new file mode 100644
index 0000000000..323e7c4128
Binary files /dev/null and b/assets/japro/hud/mod/thermal.png differ
diff --git a/assets/japro/hud/mod/thermal_alt.png b/assets/japro/hud/mod/thermal_alt.png
new file mode 100644
index 0000000000..4ff5a6527e
Binary files /dev/null and b/assets/japro/hud/mod/thermal_alt.png differ
diff --git a/assets/japro/hud/mod/turret.png b/assets/japro/hud/mod/turret.png
new file mode 100644
index 0000000000..b4aff52029
Binary files /dev/null and b/assets/japro/hud/mod/turret.png differ
diff --git a/assets/japro/hud/mod/water.png b/assets/japro/hud/mod/water.png
new file mode 100644
index 0000000000..576c855d5c
Binary files /dev/null and b/assets/japro/hud/mod/water.png differ
diff --git a/codemp/cgame/CMakeLists.txt b/codemp/cgame/CMakeLists.txt
index 3993c66e66..a9e68a7e85 100644
--- a/codemp/cgame/CMakeLists.txt
+++ b/codemp/cgame/CMakeLists.txt
@@ -63,6 +63,7 @@ set(MPCGameCgameFiles
"${MPDir}/cgame/cg_effects.c"
"${MPDir}/cgame/cg_ents.c"
"${MPDir}/cgame/cg_event.c"
+ "${MPDir}/cgame/cg_hud.c"
"${MPDir}/cgame/cg_info.c"
"${MPDir}/cgame/cg_light.c"
"${MPDir}/cgame/cg_localents.c"
@@ -91,11 +92,14 @@ set(MPCGameCgameFiles
"${MPDir}/cgame/fx_force.c"
"${MPDir}/cgame/fx_heavyrepeater.c"
"${MPDir}/cgame/fx_rocketlauncher.c"
+ "${MPDir}/cgame/hud_obituary.c"
+ "${MPDir}/cgame/hud_shared.c"
"${MPDir}/cgame/animtable.h"
"${MPDir}/cgame/cg_local.h"
"${MPDir}/cgame/cg_public.h"
"${MPDir}/cgame/cg_xcvar.h"
"${MPDir}/cgame/fx_local.h"
+ "${MPDir}/cgame/hud_local.h"
)
source_group("cgame" FILES ${MPCGameCgameFiles})
set(MPCGameFiles ${MPCGameFiles} ${MPCGameCgameFiles})
diff --git a/codemp/cgame/cg_draw.c b/codemp/cgame/cg_draw.c
index 085adceaee..e58f79041a 100644
--- a/codemp/cgame/cg_draw.c
+++ b/codemp/cgame/cg_draw.c
@@ -7057,7 +7057,6 @@ void CG_AddSpeed(void)
#define SPEEDOMETER_MIN_RANGE 900
#define SPEED_MED 1000.f
#define SPEED_FAST 1600.f
-#define Vector4Copy( a, b ) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
#define VectorLerp( f, s, e, r ) ((r)[0]=(s)[0]+(f)*((e)[0]-(s)[0]),\
(r)[1]=(s)[1]+(f)*((e)[1]-(s)[1]),\
(r)[2]=(s)[2]+(f)*((e)[2]-(s)[2]))
@@ -11280,6 +11279,9 @@ static void CG_Draw2D( void ) {
return;
}
+ if(cg_killfeed.integer)
+ CG_Draw2DNew( );
+
CG_Draw2DScreenTints();
if (cg.snap->ps.rocketLockIndex != ENTITYNUM_NONE && (cg.time - cg.snap->ps.rocketLockTime) > 0)
diff --git a/codemp/cgame/cg_event.c b/codemp/cgame/cg_event.c
index 9f67c35f26..996528ac44 100644
--- a/codemp/cgame/cg_event.c
+++ b/codemp/cgame/cg_event.c
@@ -150,300 +150,298 @@ static void CG_Obituary( entityState_t *ent ) {
Com_sprintf(targetName, sizeof(targetName), "%s%s", targetInfo->name, S_COLOR_WHITE);
targetInfo->deaths++;
- // check for single client messages
- switch( mod ) {
- case MOD_SUICIDE:
- case MOD_FALLING:
- case MOD_CRUSH:
- case MOD_WATER:
- case MOD_SLIME:
- case MOD_LAVA:
- case MOD_TRIGGER_HURT:
- message = "DIED_GENERIC";
- break;
- case MOD_TARGET_LASER:
- message = "DIED_LASER";
- break;
- default:
- message = NULL;
- break;
- }
-
- // Attacker killed themselves. Ridicule them for it.
- if (attacker == target) {
- gender = targetInfo->gender;
- switch (mod) {
- case MOD_BRYAR_PISTOL:
- case MOD_BRYAR_PISTOL_ALT:
- case MOD_BLASTER:
- case MOD_TURBLAST:
- case MOD_DISRUPTOR:
- case MOD_DISRUPTOR_SPLASH:
- case MOD_DISRUPTOR_SNIPER:
- case MOD_BOWCASTER:
- case MOD_REPEATER:
- case MOD_REPEATER_ALT:
- case MOD_FLECHETTE:
- if ( gender == GENDER_FEMALE )
- message = "SUICIDE_SHOT_FEMALE";
- else if ( gender == GENDER_NEUTER )
- message = "SUICIDE_SHOT_GENDERLESS";
- else
- message = "SUICIDE_SHOT_MALE";
- break;
- case MOD_REPEATER_ALT_SPLASH:
- case MOD_FLECHETTE_ALT_SPLASH:
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- case MOD_ROCKET_HOMING:
- case MOD_ROCKET_HOMING_SPLASH:
- case MOD_THERMAL:
- case MOD_THERMAL_SPLASH:
- case MOD_TRIP_MINE_SPLASH:
- case MOD_TIMED_MINE_SPLASH:
- case MOD_DET_PACK_SPLASH:
- case MOD_VEHICLE:
- case MOD_CONC:
- case MOD_CONC_ALT:
- if ( gender == GENDER_FEMALE )
- message = "SUICIDE_EXPLOSIVES_FEMALE";
- else if ( gender == GENDER_NEUTER )
- message = "SUICIDE_EXPLOSIVES_GENDERLESS";
- else
- message = "SUICIDE_EXPLOSIVES_MALE";
- break;
- case MOD_DEMP2:
- if ( gender == GENDER_FEMALE )
- message = "SUICIDE_ELECTROCUTED_FEMALE";
- else if ( gender == GENDER_NEUTER )
- message = "SUICIDE_ELECTROCUTED_GENDERLESS";
- else
- message = "SUICIDE_ELECTROCUTED_MALE";
- break;
- case MOD_FALLING:
- if ( gender == GENDER_FEMALE )
- message = "SUICIDE_FALLDEATH_FEMALE";
- else if ( gender == GENDER_NEUTER )
- message = "SUICIDE_FALLDEATH_GENDERLESS";
- else
- message = "SUICIDE_FALLDEATH_MALE";
- break;
- default:
- if ( gender == GENDER_FEMALE )
- message = "SUICIDE_GENERICDEATH_FEMALE";
- else if ( gender == GENDER_NEUTER )
- message = "SUICIDE_GENERICDEATH_GENDERLESS";
- else
- message = "SUICIDE_GENERICDEATH_MALE";
- break;
- }
- }
-
- if (target != attacker && target < MAX_CLIENTS && attacker < MAX_CLIENTS)
- {
- goto clientkilled;
- }
-
- if (message) {
- gender = targetInfo->gender;
-
- if (!message[0])
- {
- if ( gender == GENDER_FEMALE )
- message = "SUICIDE_GENERICDEATH_FEMALE";
- else if ( gender == GENDER_NEUTER )
- message = "SUICIDE_GENERICDEATH_GENDERLESS";
- else
- message = "SUICIDE_GENERICDEATH_MALE";
- }
- message = (char *)CG_GetStringEdString("MP_INGAME", message);
-
- trap->Print( "%s %s\n", targetName, message);
- return;
- }
-
-clientkilled:
-
- // check for kill messages from the current clientNum
- if ( attacker == cg.snap->ps.clientNum ) {
- char s[MAX_STRING_CHARS] = {0};
-
- if ( cg_killMessage.integer != 2 && cgs.gametype < GT_TEAM && cgs.gametype != GT_DUEL && cgs.gametype != GT_POWERDUEL ) {
- if (cgs.gametype == GT_JEDIMASTER &&
- attacker < MAX_CLIENTS &&
- !ent->isJediMaster &&
- !cg.snap->ps.isJediMaster &&
- CG_ThereIsAMaster())
- {
- char part1[512];
- char part2[512];
- trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
- trap->SE_GetStringTextString("MP_INGAME_JMKILLED_NOTJM", part2, sizeof(part2));
- Com_sprintf(s, sizeof(s), "%s %s\n%s\n", part1, targetName, part2);
- }
- else if (cgs.gametype == GT_JEDIMASTER &&
- attacker < MAX_CLIENTS &&
- !ent->isJediMaster &&
- !cg.snap->ps.isJediMaster)
- { //no JM, saber must be out
- char part1[512];
- trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
- /*
- kmsg1 = "for 0 points.\nGo for the saber!";
- strcpy(part2, kmsg1);
-
- Com_sprintf(s, sizeof(s), "%s %s %s\n", part1, targetName, part2);
- */
- Com_sprintf(s, sizeof(s), "%s %s\n", part1, targetName);
- }
- else if (cgs.gametype == GT_POWERDUEL)
- {
- Q_strncpyz(s, "", sizeof(s));
- }
- else
- {
- char sPlaceWith[256];
- char sKilledStr[256];
- trap->SE_GetStringTextString("MP_INGAME_PLACE_WITH", sPlaceWith, sizeof(sPlaceWith));
- trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr));
-
- Com_sprintf(s, sizeof(s), "%s %s\n%s %s %i.", sKilledStr, targetName,
- CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
- sPlaceWith,
- cg.snap->ps.persistant[PERS_SCORE] );
- }
- } else {
- char sKilledStr[256];
- trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr));
- Com_sprintf(s, sizeof(s), "%s %s", sKilledStr, targetName );
- }
-
- if (cg_killMessage.integer == 1 || cg_killMessage.integer == 2)//JAPRO - Clientside - Toggle Kill award message
- CG_CenterPrintMultiKill( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
- else if (cg_killMessage.integer > 2)//JAPRO - Clientside - Toggle Kill award message
- CG_CenterPrintMultiKill( s, SCREEN_HEIGHT * 0.10, BIGCHAR_WIDTH );
- }
-
- // check for double client messages
- if ( !attackerInfo || !attackerInfo->infoValid ) {
- attacker = ENTITYNUM_WORLD;
- Q_strncpyz( attackerName, "noname", sizeof(attackerName) );
- } else {
- Com_sprintf(attackerName, sizeof(attackerName), "%s%s", attackerInfo->name, S_COLOR_WHITE);
- // check for kill messages about the current clientNum
- if ( target == cg.snap->ps.clientNum ) {
- Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
- }
- }
-
- if ( attacker != ENTITYNUM_WORLD ) {
- switch (mod) {
- case MOD_STUN_BATON:
- message = "KILLED_STUN";
- break;
- case MOD_MELEE:
- message = "KILLED_MELEE";
- break;
- case MOD_SABER:
- message = "KILLED_SABER";
- break;
- case MOD_BRYAR_PISTOL:
- case MOD_BRYAR_PISTOL_ALT:
- message = "KILLED_BRYAR";
- break;
- case MOD_BLASTER:
- message = "KILLED_BLASTER";
- break;
- case MOD_TURBLAST:
- message = "KILLED_BLASTER";
- break;
- case MOD_DISRUPTOR:
- case MOD_DISRUPTOR_SPLASH:
- message = "KILLED_DISRUPTOR";
- break;
- case MOD_DISRUPTOR_SNIPER:
- message = "KILLED_DISRUPTORSNIPE";
- break;
- case MOD_BOWCASTER:
- message = "KILLED_BOWCASTER";
- break;
- case MOD_REPEATER:
- message = "KILLED_REPEATER";
- break;
- case MOD_REPEATER_ALT:
- case MOD_REPEATER_ALT_SPLASH:
- message = "KILLED_REPEATERALT";
- break;
- case MOD_DEMP2:
- case MOD_DEMP2_ALT:
- message = "KILLED_DEMP2";
- break;
- case MOD_FLECHETTE:
- message = "KILLED_FLECHETTE";
- break;
- case MOD_FLECHETTE_ALT_SPLASH:
- message = "KILLED_FLECHETTE_MINE";
- break;
- case MOD_ROCKET:
- case MOD_ROCKET_SPLASH:
- message = "KILLED_ROCKET";
- break;
- case MOD_ROCKET_HOMING:
- case MOD_ROCKET_HOMING_SPLASH:
- message = "KILLED_ROCKET_HOMING";
- break;
- case MOD_THERMAL:
- case MOD_THERMAL_SPLASH:
- message = "KILLED_THERMAL";
- break;
- case MOD_TRIP_MINE_SPLASH:
- message = "KILLED_TRIPMINE";
- break;
- case MOD_TIMED_MINE_SPLASH:
- message = "KILLED_TRIPMINE_TIMED";
- break;
- case MOD_DET_PACK_SPLASH:
- message = "KILLED_DETPACK";
- break;
- case MOD_VEHICLE:
- case MOD_CONC:
- case MOD_CONC_ALT:
- message = "KILLED_GENERIC";
- break;
- case MOD_FORCE_DARK:
- message = "KILLED_DARKFORCE";
- break;
- case MOD_SENTRY:
- message = "KILLED_SENTRY";
- break;
- case MOD_TELEFRAG:
- message = "KILLED_TELEFRAG";
- break;
- case MOD_CRUSH:
- message = "KILLED_GENERIC";//"KILLED_FORCETOSS";
- break;
- case MOD_FALLING:
- message = "KILLED_FORCETOSS";
- break;
- case MOD_TRIGGER_HURT:
- message = "KILLED_GENERIC";//"KILLED_FORCETOSS";
- break;
- default:
- message = "KILLED_GENERIC";
- break;
- }
-
- if (message) {
- message = (char *)CG_GetStringEdString("MP_INGAME", message);
-
- trap->Print( "%s %s %s\n",
- targetName, message, attackerName);
- return;
- }
- }
-
- // we don't know what it was
- trap->Print( "%s %s\n", targetName, (char *)CG_GetStringEdString("MP_INGAME", "DIED_GENERIC") );
+ if(cg_killfeed.integer){
+ CG_AddObituary( attacker, target, mod );
+ }
+ if (cg_killfeed.integer != 1){
+ // check for single client messages
+ switch (mod) {
+ case MOD_SUICIDE:
+ case MOD_FALLING:
+ case MOD_CRUSH:
+ case MOD_WATER:
+ case MOD_SLIME:
+ case MOD_LAVA:
+ case MOD_TRIGGER_HURT:
+ message = "DIED_GENERIC";
+ break;
+ case MOD_TARGET_LASER:
+ message = "DIED_LASER";
+ break;
+ default:
+ message = NULL;
+ break;
+ }
+
+ // Attacker killed themselves. Ridicule them for it.
+ if (attacker == target) {
+ gender = targetInfo->gender;
+ switch (mod) {
+ case MOD_BRYAR_PISTOL:
+ case MOD_BRYAR_PISTOL_ALT:
+ case MOD_BLASTER:
+ case MOD_TURBLAST:
+ case MOD_DISRUPTOR:
+ case MOD_DISRUPTOR_SPLASH:
+ case MOD_DISRUPTOR_SNIPER:
+ case MOD_BOWCASTER:
+ case MOD_REPEATER:
+ case MOD_REPEATER_ALT:
+ case MOD_FLECHETTE:
+ if (gender == GENDER_FEMALE)
+ message = "SUICIDE_SHOT_FEMALE";
+ else if (gender == GENDER_NEUTER)
+ message = "SUICIDE_SHOT_GENDERLESS";
+ else
+ message = "SUICIDE_SHOT_MALE";
+ break;
+ case MOD_REPEATER_ALT_SPLASH:
+ case MOD_FLECHETTE_ALT_SPLASH:
+ case MOD_ROCKET:
+ case MOD_ROCKET_SPLASH:
+ case MOD_ROCKET_HOMING:
+ case MOD_ROCKET_HOMING_SPLASH:
+ case MOD_THERMAL:
+ case MOD_THERMAL_SPLASH:
+ case MOD_TRIP_MINE_SPLASH:
+ case MOD_TIMED_MINE_SPLASH:
+ case MOD_DET_PACK_SPLASH:
+ case MOD_VEHICLE:
+ case MOD_CONC:
+ case MOD_CONC_ALT:
+ if (gender == GENDER_FEMALE)
+ message = "SUICIDE_EXPLOSIVES_FEMALE";
+ else if (gender == GENDER_NEUTER)
+ message = "SUICIDE_EXPLOSIVES_GENDERLESS";
+ else
+ message = "SUICIDE_EXPLOSIVES_MALE";
+ break;
+ case MOD_DEMP2:
+ if (gender == GENDER_FEMALE)
+ message = "SUICIDE_ELECTROCUTED_FEMALE";
+ else if (gender == GENDER_NEUTER)
+ message = "SUICIDE_ELECTROCUTED_GENDERLESS";
+ else
+ message = "SUICIDE_ELECTROCUTED_MALE";
+ break;
+ case MOD_FALLING:
+ if (gender == GENDER_FEMALE)
+ message = "SUICIDE_FALLDEATH_FEMALE";
+ else if (gender == GENDER_NEUTER)
+ message = "SUICIDE_FALLDEATH_GENDERLESS";
+ else
+ message = "SUICIDE_FALLDEATH_MALE";
+ break;
+ default:
+ if (gender == GENDER_FEMALE)
+ message = "SUICIDE_GENERICDEATH_FEMALE";
+ else if (gender == GENDER_NEUTER)
+ message = "SUICIDE_GENERICDEATH_GENDERLESS";
+ else
+ message = "SUICIDE_GENERICDEATH_MALE";
+ break;
+ }
+ }
+
+ if (target != attacker && target < MAX_CLIENTS && attacker < MAX_CLIENTS) {
+ goto clientkilled;
+ }
+
+ if (message) {
+ gender = targetInfo->gender;
+
+ if (!message[0]) {
+ if (gender == GENDER_FEMALE)
+ message = "SUICIDE_GENERICDEATH_FEMALE";
+ else if (gender == GENDER_NEUTER)
+ message = "SUICIDE_GENERICDEATH_GENDERLESS";
+ else
+ message = "SUICIDE_GENERICDEATH_MALE";
+ }
+ message = (char *) CG_GetStringEdString("MP_INGAME", message);
+
+ trap->Print("%s %s\n", targetName, message);
+ return;
+ }
+
+ clientkilled:
+
+ // check for kill messages from the current clientNum
+ if (attacker == cg.snap->ps.clientNum) {
+ char s[MAX_STRING_CHARS] = {0};
+
+ if (cg_killMessage.integer != 2 && cgs.gametype < GT_TEAM && cgs.gametype != GT_DUEL &&
+ cgs.gametype != GT_POWERDUEL) {
+ if (cgs.gametype == GT_JEDIMASTER &&
+ attacker < MAX_CLIENTS &&
+ !ent->isJediMaster &&
+ !cg.snap->ps.isJediMaster &&
+ CG_ThereIsAMaster()) {
+ char part1[512];
+ char part2[512];
+ trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
+ trap->SE_GetStringTextString("MP_INGAME_JMKILLED_NOTJM", part2, sizeof(part2));
+ Com_sprintf(s, sizeof(s), "%s %s\n%s\n", part1, targetName, part2);
+ } else if (cgs.gametype == GT_JEDIMASTER &&
+ attacker < MAX_CLIENTS &&
+ !ent->isJediMaster &&
+ !cg.snap->ps.isJediMaster) { //no JM, saber must be out
+ char part1[512];
+ trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
+ /*
+ kmsg1 = "for 0 points.\nGo for the saber!";
+ strcpy(part2, kmsg1);
+
+ Com_sprintf(s, sizeof(s), "%s %s %s\n", part1, targetName, part2);
+ */
+ Com_sprintf(s, sizeof(s), "%s %s\n", part1, targetName);
+ } else if (cgs.gametype == GT_POWERDUEL) {
+ Q_strncpyz(s, "", sizeof(s));
+ } else {
+ char sPlaceWith[256];
+ char sKilledStr[256];
+ trap->SE_GetStringTextString("MP_INGAME_PLACE_WITH", sPlaceWith, sizeof(sPlaceWith));
+ trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr));
+
+ Com_sprintf(s, sizeof(s), "%s %s\n%s %s %i.", sKilledStr, targetName,
+ CG_PlaceString(cg.snap->ps.persistant[PERS_RANK] + 1),
+ sPlaceWith,
+ cg.snap->ps.persistant[PERS_SCORE]);
+ }
+ } else {
+ char sKilledStr[256];
+ trap->SE_GetStringTextString("MP_INGAME_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr));
+ Com_sprintf(s, sizeof(s), "%s %s", sKilledStr, targetName);
+ }
+
+ if (cg_killMessage.integer == 1 ||
+ cg_killMessage.integer == 2)//JAPRO - Clientside - Toggle Kill award message
+ CG_CenterPrintMultiKill(s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH);
+ else if (cg_killMessage.integer > 2)//JAPRO - Clientside - Toggle Kill award message
+ CG_CenterPrintMultiKill(s, SCREEN_HEIGHT * 0.10, BIGCHAR_WIDTH);
+ }
+
+ // check for double client messages
+ if (!attackerInfo || !attackerInfo->infoValid) {
+ attacker = ENTITYNUM_WORLD;
+ Q_strncpyz(attackerName, "noname", sizeof(attackerName));
+ } else {
+ Com_sprintf(attackerName, sizeof(attackerName), "%s%s", attackerInfo->name, S_COLOR_WHITE);
+ // check for kill messages about the current clientNum
+ if (target == cg.snap->ps.clientNum) {
+ Q_strncpyz(cg.killerName, attackerName, sizeof(cg.killerName));
+ }
+ }
+
+ if (attacker != ENTITYNUM_WORLD) {
+ switch (mod) {
+ case MOD_STUN_BATON:
+ message = "KILLED_STUN";
+ break;
+ case MOD_MELEE:
+ message = "KILLED_MELEE";
+ break;
+ case MOD_SABER:
+ message = "KILLED_SABER";
+ break;
+ case MOD_BRYAR_PISTOL:
+ case MOD_BRYAR_PISTOL_ALT:
+ message = "KILLED_BRYAR";
+ break;
+ case MOD_BLASTER:
+ message = "KILLED_BLASTER";
+ break;
+ case MOD_TURBLAST:
+ message = "KILLED_BLASTER";
+ break;
+ case MOD_DISRUPTOR:
+ case MOD_DISRUPTOR_SPLASH:
+ message = "KILLED_DISRUPTOR";
+ break;
+ case MOD_DISRUPTOR_SNIPER:
+ message = "KILLED_DISRUPTORSNIPE";
+ break;
+ case MOD_BOWCASTER:
+ message = "KILLED_BOWCASTER";
+ break;
+ case MOD_REPEATER:
+ message = "KILLED_REPEATER";
+ break;
+ case MOD_REPEATER_ALT:
+ case MOD_REPEATER_ALT_SPLASH:
+ message = "KILLED_REPEATERALT";
+ break;
+ case MOD_DEMP2:
+ case MOD_DEMP2_ALT:
+ message = "KILLED_DEMP2";
+ break;
+ case MOD_FLECHETTE:
+ message = "KILLED_FLECHETTE";
+ break;
+ case MOD_FLECHETTE_ALT_SPLASH:
+ message = "KILLED_FLECHETTE_MINE";
+ break;
+ case MOD_ROCKET:
+ case MOD_ROCKET_SPLASH:
+ message = "KILLED_ROCKET";
+ break;
+ case MOD_ROCKET_HOMING:
+ case MOD_ROCKET_HOMING_SPLASH:
+ message = "KILLED_ROCKET_HOMING";
+ break;
+ case MOD_THERMAL:
+ case MOD_THERMAL_SPLASH:
+ message = "KILLED_THERMAL";
+ break;
+ case MOD_TRIP_MINE_SPLASH:
+ message = "KILLED_TRIPMINE";
+ break;
+ case MOD_TIMED_MINE_SPLASH:
+ message = "KILLED_TRIPMINE_TIMED";
+ break;
+ case MOD_DET_PACK_SPLASH:
+ message = "KILLED_DETPACK";
+ break;
+ case MOD_VEHICLE:
+ case MOD_CONC:
+ case MOD_CONC_ALT:
+ message = "KILLED_GENERIC";
+ break;
+ case MOD_FORCE_DARK:
+ message = "KILLED_DARKFORCE";
+ break;
+ case MOD_SENTRY:
+ message = "KILLED_SENTRY";
+ break;
+ case MOD_TELEFRAG:
+ message = "KILLED_TELEFRAG";
+ break;
+ case MOD_CRUSH:
+ message = "KILLED_GENERIC";//"KILLED_FORCETOSS";
+ break;
+ case MOD_FALLING:
+ message = "KILLED_FORCETOSS";
+ break;
+ case MOD_TRIGGER_HURT:
+ message = "KILLED_GENERIC";//"KILLED_FORCETOSS";
+ break;
+ default:
+ message = "KILLED_GENERIC";
+ break;
+ }
+
+ if (message) {
+ message = (char *) CG_GetStringEdString("MP_INGAME", message);
+
+ trap->Print("%s %s %s\n",
+ targetName, message, attackerName);
+ return;
+ }
+ }
+
+ // we don't know what it was
+ trap->Print("%s %s\n", targetName, (char *) CG_GetStringEdString("MP_INGAME", "DIED_GENERIC"));
+ }
}
//==========================================================================
diff --git a/codemp/cgame/cg_hud.c b/codemp/cgame/cg_hud.c
new file mode 100644
index 0000000000..bf83cf5057
--- /dev/null
+++ b/codemp/cgame/cg_hud.c
@@ -0,0 +1,49 @@
+/*
+===========================================================================
+Copyright (C) 1999 - 2005, Id Software, Inc.
+Copyright (C) 2000 - 2013, Raven Software, Inc.
+Copyright (C) 2001 - 2013, Activision, Inc.
+Copyright (C) 2005 - 2015, ioquake3 contributors
+Copyright (C) 2013 - 2015, OpenJK contributors
+Copyright (C) 2015 - 2021, EternalJK contributors
+Copyright (C) 2015 - 2023, TaystJK contributors
+
+
+This file is part of the TaystJK source code.
+
+TaystJK is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see .
+===========================================================================
+*/
+
+//
+// cg_hud.c - New HUD
+//
+
+#include "cg_local.h"
+#include "hud_local.h"
+
+void CG_InitNewHUD( void ) {
+ HUD_InitMedia();
+ HUD_InitObituary();
+}
+
+/*
+=================
+CG_Draw2DNew
+=================
+*/
+
+void CG_Draw2DNew( void ) {
+ trap->R_SetColor( NULL );
+ HUD_DrawObituary();
+}
diff --git a/codemp/cgame/cg_local.h b/codemp/cgame/cg_local.h
index 72dbeb66e4..d63e9dc8a0 100644
--- a/codemp/cgame/cg_local.h
+++ b/codemp/cgame/cg_local.h
@@ -35,6 +35,8 @@ along with this program; if not, see .
// If you absolutely need something stored, it can either be kept
// by the server in the server stored userinfos, or stashed in a cvar.
+#define Vector4Copy( a, b ) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+
#define POWERUP_BLINKS 5
#define POWERUP_BLINK_TIME 1000
@@ -2660,6 +2662,9 @@ void CG_Respawn( void );
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
void CG_CheckChangedPredictableEvents( playerState_t *ps );
+void CG_InitNewHUD( void );
+void CG_Draw2DNew( void );
+void CG_AddObituary( int killer, int victim, meansOfDeath_t mod );
//
// cg_siege.c
diff --git a/codemp/cgame/cg_main.c b/codemp/cgame/cg_main.c
index 5fd9b58db2..cc1399c03b 100644
--- a/codemp/cgame/cg_main.c
+++ b/codemp/cgame/cg_main.c
@@ -3193,6 +3193,7 @@ Ghoul2 Insert End
#endif
CG_InitMarkPolys();
+ CG_InitNewHUD();
// remove the last loading update
cg.infoScreenText[0] = 0;
diff --git a/codemp/cgame/cg_xcvar.h b/codemp/cgame/cg_xcvar.h
index 29255da68f..c18a665c55 100644
--- a/codemp/cgame/cg_xcvar.h
+++ b/codemp/cgame/cg_xcvar.h
@@ -409,7 +409,13 @@ XCVAR_DEF( cg_disruptorSpiralColor, "xff2200", NULL, CVAR_ARCHIVE )
XCVAR_DEF( cg_disruptorNew, "0", NULL, CVAR_ARCHIVE )
XCVAR_DEF( cg_ambientSounds, "1", NULL, CVAR_ARCHIVE )
-
+XCVAR_DEF( cg_killfeed, "0", NULL, CVAR_ARCHIVE )
+XCVAR_DEF( cg_killfeedX, "0", NULL, CVAR_ARCHIVE )
+XCVAR_DEF( cg_killfeedY, "0", NULL, CVAR_ARCHIVE )
+XCVAR_DEF( cg_killfeedAlignment, "0", NULL, CVAR_ARCHIVE )
+XCVAR_DEF( cg_killfeedIconSize, "12", NULL, CVAR_ARCHIVE )
+XCVAR_DEF( cg_killfeedTextSize, "0.8", NULL, CVAR_ARCHIVE )
+XCVAR_DEF( cg_killfeedColors, "0", NULL, CVAR_ARCHIVE )
#undef XCVAR_DEF
diff --git a/codemp/cgame/hud_local.h b/codemp/cgame/hud_local.h
new file mode 100644
index 0000000000..e432e02808
--- /dev/null
+++ b/codemp/cgame/hud_local.h
@@ -0,0 +1,68 @@
+/*
+===========================================================================
+Copyright (C) 1999 - 2005, Id Software, Inc.
+Copyright (C) 2000 - 2013, Raven Software, Inc.
+Copyright (C) 2001 - 2013, Activision, Inc.
+Copyright (C) 2005 - 2015, ioquake3 contributors
+Copyright (C) 2013 - 2015, OpenJK contributors
+Copyright (C) 2015 - 2021, EternalJK contributors
+Copyright (C) 2015 - 2023, TaystJK contributors
+
+
+This file is part of the TaystJK source code.
+
+TaystJK is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see .
+===========================================================================
+*/
+
+#if !defined( HUD_LOCAL_H )
+#define HUD_LOCAL_H
+
+
+#define MAX_OBITUARY 8
+#define OBITUARY_TIMEOUT 2500
+#define OBITUARY_FADEOUTTIME 2000
+#define OBITUARY_ICON_SIZE 18.0f
+#define OBITUARY_TEXT_SIZE 2.0f
+
+#define OBITUARY_PADDING_SCALAR 0.2f
+
+enum KillfeedAlignment
+{
+ KF_RIGHT,
+ KF_LEFT,
+ KF_CENTER,
+};
+
+typedef struct {
+ int killer;
+ int victim;
+ meansOfDeath_t mod;
+ int time;
+} obituary_t;
+
+typedef struct {
+ qhandle_t deathIcon; // for generic kill message
+ qhandle_t modIcon[MOD_MAX]; // means of death icons
+} hudMedia_t;
+
+extern hudMedia_t hm;
+extern vec4_t hudModColors[MOD_MAX];
+extern const char *hudModIcons[MOD_MAX];
+
+// get all the required assets
+void HUD_InitMedia( void );
+void HUD_InitObituary( void );
+void HUD_DrawObituary( void );
+void HUD_InitKFAlignment( void );
+#endif
diff --git a/codemp/cgame/hud_obituary.c b/codemp/cgame/hud_obituary.c
new file mode 100644
index 0000000000..b7173d6035
--- /dev/null
+++ b/codemp/cgame/hud_obituary.c
@@ -0,0 +1,228 @@
+/*
+===========================================================================
+Copyright (C) 1999 - 2005, Id Software, Inc.
+Copyright (C) 2000 - 2013, Raven Software, Inc.
+Copyright (C) 2001 - 2013, Activision, Inc.
+Copyright (C) 2005 - 2015, ioquake3 contributors
+Copyright (C) 2013 - 2015, OpenJK contributors
+Copyright (C) 2015 - 2021, EternalJK contributors
+Copyright (C) 2015 - 2023, TaystJK contributors
+
+
+This file is part of the TaystJK source code.
+
+TaystJK is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see .
+===========================================================================
+*/
+
+#include "../qcommon/q_shared.h"
+#include "cg_local.h"
+#include "hud_local.h"
+
+static int killfeedAlignment;
+static obituary_t hudObituary[MAX_OBITUARY];
+static int hudNumObituary;
+static float kfXOffset, kfYOffset, kfTextSize, kfIconSize;
+void HUD_InitObituary(void) {
+ hudNumObituary = 0;
+}
+
+void HUD_InitKFAlignment(void) {
+ killfeedAlignment = cg_killfeedAlignment.integer;
+ kfXOffset = cg_killfeedX.value;
+ kfYOffset = cg_killfeedY.value;
+ kfIconSize = cg_killfeedIconSize.value;
+ kfTextSize = cg_killfeedTextSize.value;
+}
+
+static void HUD_PurgeObituary(void) {
+ static obituary_t obituary[MAX_OBITUARY];
+ int i, numObituary;
+ memcpy(obituary, hudObituary, sizeof(obituary));
+ numObituary = 0;
+ for (i = 0; i < hudNumObituary; i++) {
+ if (cg.time - obituary[i].time > OBITUARY_TIMEOUT) {
+ continue;
+ }
+ memcpy( &hudObituary[numObituary], &obituary[i], sizeof(obituary_t));
+ numObituary++;
+ }
+ hudNumObituary = numObituary;
+}
+
+void HUD_DrawObituary(void) {
+ qboolean suicide = qfalse;
+ static float color[4] = {1.0f,1.0f,1.0f,1.0f};
+ static float blueTeam[4] = {0.0f,0.0f,1.0f,0.15f};
+ static float redTeam[4] = {1.0f,0.0f,0.0f,0.15f};
+ static float playerColor[4] = {0.0f,1.0f,0.0f,0.15f};
+ static float neutralColor[4] = {0.6f,0.6f,0.6f, 0.15f };
+ float x, y, iconSize, iconHeight, iconWidth, padding, xPadding, yPadding, textScale, textHeight, killerTextHeight, victimTextHeight, boxCenterY, boxCenterX;
+ float wepColor[4], killerColor[4], victimColor[4];
+ float killerTextWidth, victimTextWidth, totalWidth, maxHeight, victimTextStartY, killerTextStartY;
+ obituary_t *p;
+ qhandle_t deathIcon;
+
+ HUD_PurgeObituary();
+
+ // Set up the killfeed
+ if(cg_killfeedIconSize.value)
+ iconSize = kfIconSize;
+ else
+ iconSize = OBITUARY_ICON_SIZE;
+
+ if(cg_killfeedTextSize.value)
+ textScale = kfTextSize;
+ else
+ textScale = OBITUARY_TEXT_SIZE;
+
+ y = 10.0f + kfYOffset;
+ padding = OBITUARY_PADDING_SCALAR;
+ iconWidth = (iconSize * cgs.widthRatioCoef);
+ iconHeight = iconSize;
+
+ for (p = hudObituary; p < hudObituary + hudNumObituary; p++) {
+ // Set the method of death icon
+ if(hm.modIcon[p->mod])
+ deathIcon = hm.modIcon[p->mod];
+ else
+ deathIcon = hm.modIcon[MOD_UNKNOWN];
+ // Set the icons' color
+ if(cg_killfeedColors.integer){
+ wepColor[0] = hudModColors[p->mod][0];
+ wepColor[1] = hudModColors[p->mod][1];
+ wepColor[2] = hudModColors[p->mod][2];
+ } else {
+ wepColor[0] = color[0];
+ wepColor[1] = color[0];
+ wepColor[2] = color[0];
+ }
+ // Set the box colors based on game type
+ if (cgs.gametype >= GT_TEAM) {
+ // Use a neutral grey color
+ Vector4Copy(neutralColor, victimColor);
+ Vector4Copy(neutralColor, killerColor);
+ // Get the killer's team color
+ if (cgs.clientinfo[p->killer].team == TEAM_BLUE) {
+ Vector4Copy(blueTeam, killerColor);
+ } else if (cgs.clientinfo[p->killer].team == TEAM_RED) {
+ Vector4Copy(redTeam, killerColor);
+ }
+ // Check if it's the local player
+ if (p->killer == cg.snap->ps.clientNum) {
+ Vector4Copy(playerColor, killerColor);
+ }
+ // Get the victim's team color
+ if (cgs.clientinfo[p->victim].team == TEAM_BLUE) {
+ Vector4Copy(blueTeam, victimColor);
+ } else if (cgs.clientinfo[p->victim].team == TEAM_RED) {
+ Vector4Copy(redTeam, victimColor);
+ }
+ // Check if it's the local player
+ if (p->victim == cg.snap->ps.clientNum) {
+ Vector4Copy(playerColor, victimColor);
+ }
+ } else {
+ // Use a neutral grey color
+ Vector4Copy(neutralColor, victimColor);
+ Vector4Copy(neutralColor, killerColor);
+ // Unless it's the local player
+ if (p->killer == cg.snap->ps.clientNum) {
+ Vector4Copy(playerColor, killerColor);
+ }
+ if (p->victim == cg.snap->ps.clientNum) {
+ Vector4Copy(playerColor, victimColor);
+ }
+ }
+ // Fade the obituaries
+ if (cg.time - p->time > OBITUARY_FADEOUTTIME) {
+ color[3] = 1.0f - ((float)cg.time - (float)p->time - OBITUARY_FADEOUTTIME) / (OBITUARY_TIMEOUT - OBITUARY_FADEOUTTIME);
+ } else {
+ color[3] = 1.0f;
+ }
+ // Only fade the boxes if the new fade is less than our current opacity
+ killerColor[3] = fminf(0.25f * color[3], killerColor[3]);
+ victimColor[3] = fminf(0.25f * color[3], victimColor[3]);
+ wepColor[3] = color[3];
+ //Get the sizes of everything
+ if((p->killer == p->victim) || (p->killer == ENTITYNUM_WORLD)) { //is it a suicide
+ suicide = qtrue;
+ victimTextWidth = CG_Text_Width(cgs.clientinfo[p->victim].name, textScale, FONT_MEDIUM);
+ victimTextHeight = (float)CG_Text_Height(cgs.clientinfo[p->victim].name, textScale, FONT_MEDIUM);
+ textHeight = victimTextHeight;
+ } else {
+ victimTextWidth = CG_Text_Width(cgs.clientinfo[p->victim].name, textScale, FONT_MEDIUM);
+ victimTextHeight = (float)CG_Text_Height(cgs.clientinfo[p->victim].name, textScale, FONT_MEDIUM);
+ killerTextWidth = CG_Text_Width(cgs.clientinfo[p->killer].name, textScale, FONT_MEDIUM);
+ killerTextHeight = (float)CG_Text_Height(cgs.clientinfo[p->killer].name, textScale, FONT_MEDIUM);
+ textHeight = fmaxf(killerTextHeight, victimTextHeight);
+ }
+ maxHeight = fmaxf(iconHeight, textHeight);
+ xPadding = (padding * maxHeight * cgs.widthRatioCoef);
+ yPadding = (padding * maxHeight);
+ boxCenterY = y + ((maxHeight + yPadding) / 2.0f);
+ victimTextStartY = boxCenterY - 0.75f * victimTextHeight;
+ boxCenterX = ((maxHeight * cgs.widthRatioCoef + xPadding) / 2.0f);
+ if(!suicide) {
+ killerTextStartY = boxCenterY - 0.75f * killerTextHeight;
+ totalWidth = killerTextWidth + victimTextWidth + (3.0f * xPadding) + (2.0f * boxCenterX);
+ } else {
+ totalWidth = victimTextWidth + (1.5f * xPadding) + (2.0f * boxCenterX);
+ }
+ //offset the allignment
+ switch (killfeedAlignment){
+ case KF_RIGHT:
+ x = SCREEN_WIDTH - totalWidth - (10.0f + kfXOffset) * cgs.widthRatioCoef;
+ break;
+ case KF_LEFT:
+ x = (10.0f + kfXOffset) * cgs.widthRatioCoef;
+ break;
+ case KF_CENTER:
+ x = (SCREEN_WIDTH - totalWidth) * 0.5f + kfXOffset;
+ break;
+ default:
+ x = kfXOffset;
+ }
+
+ //Draw the killfeed
+ if(!suicide) {
+ CG_FillRect(x, y, killerTextWidth + xPadding, maxHeight + yPadding, killerColor);
+ CG_Text_Paint(x + 0.5f * xPadding, killerTextStartY, textScale, color, cgs.clientinfo[p->killer].name, 0, 0, 0, FONT_MEDIUM);
+ x += killerTextWidth + xPadding;
+ }
+ trap->R_SetColor(wepColor);
+ CG_DrawPic(x + boxCenterX - 0.5f * iconWidth, boxCenterY - 0.5f * iconHeight, iconWidth, iconHeight, deathIcon);
+ trap->R_SetColor(NULL);
+ x += (boxCenterX * 2.0f);
+ CG_FillRect(x, y, victimTextWidth + xPadding, maxHeight + yPadding, victimColor);
+ CG_Text_Paint(x + (0.5f * xPadding), victimTextStartY, textScale, color, cgs.clientinfo[p->victim].name, 0, 0, 0, FONT_MEDIUM);
+
+ y += boxCenterY + yPadding;
+ }
+}
+
+void CG_AddObituary(int killer, int victim, meansOfDeath_t mod) {
+ int i;
+ HUD_InitKFAlignment();
+ if (hudNumObituary == MAX_OBITUARY) {
+ for (i = 0; i < MAX_OBITUARY - 1; i++) {
+ memcpy(&hudObituary[i], &hudObituary[i + 1], sizeof(obituary_t));
+ }
+ hudNumObituary--;
+ }
+ hudObituary[hudNumObituary].killer = killer;
+ hudObituary[hudNumObituary].victim = victim;
+ hudObituary[hudNumObituary].mod = mod;
+ hudObituary[hudNumObituary].time = cg.time;
+ hudNumObituary++;
+}
\ No newline at end of file
diff --git a/codemp/cgame/hud_shared.c b/codemp/cgame/hud_shared.c
new file mode 100644
index 0000000000..65a7627621
--- /dev/null
+++ b/codemp/cgame/hud_shared.c
@@ -0,0 +1,132 @@
+/*
+===========================================================================
+Copyright (C) 1999 - 2005, Id Software, Inc.
+Copyright (C) 2000 - 2013, Raven Software, Inc.
+Copyright (C) 2001 - 2013, Activision, Inc.
+Copyright (C) 2005 - 2015, ioquake3 contributors
+Copyright (C) 2013 - 2015, OpenJK contributors
+Copyright (C) 2015 - 2021, EternalJK contributors
+Copyright (C) 2015 - 2023, TaystJK contributors
+
+
+This file is part of the TaystJK source code.
+
+TaystJK is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see .
+===========================================================================
+*/
+
+#include "cg_local.h"
+#include "hud_local.h"
+
+vec4_t hudModColors[MOD_MAX] = {
+ { 1.0f, 1.0f, 1.0f, 1.0f }, // MOD_UNKNOWN
+ { 0.0f, 1.0f, 1.0f, 1.0f }, // MOD_STUN_BATON
+ { 1.0f, 1.0f, 0.0f, 1.0f }, // MOD_MELEE
+ { 0.5f, 0.0f, 1.0f, 1.0f }, // MOD_SABER
+ { 0.0f, 1.0f, 1.0f, 1.0f }, // MOD_BRYAR_PISTOL
+ { 0.0f, 1.0f, 1.0f, 1.0f }, // MOD_BRYAR_PISTOL_ALT
+ { 0.0f, 1.0f, 0.5f, 1.0f }, // MOD_BLASTER
+ { 0.0f, 1.0f, 0.5f, 1.0f }, // MOD_TURBLAST
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // MOD_DISRUPTOR
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // MOD_DISRUPTOR_SPLASH
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // MOD_DISRUPTOR_SNIPER
+ { 0.0f, 1.0f, 0.5f, 1.0f }, // MOD_BOWCASTER
+ { 0.0f, 0.0f, 1.0f, 1.0f }, // MOD_REPEATER
+ { 0.0f, 0.0f, 1.0f, 1.0f }, // MOD_REPEATER_ALT
+ { 0.0f, 0.0f, 1.0f, 1.0f }, // MOD_REPEATER_ALT_SPLASH
+ { 0.5f, 1.0f, 0.0f, 1.0f }, // MOD_DEMP2
+ { 0.5f, 1.0f, 0.0f, 1.0f }, // MOD_DEMP2_ALT
+ { 1.0f, 0.5f, 0.0f, 1.0f }, // MOD_FLECHETTE
+ { 1.0f, 0.5f, 0.0f, 1.0f }, // MOD_FLECHETTE_ALT_SPLASH
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // MOD_ROCKET
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // MOD_ROCKET_SPLASH
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // MOD_ROCKET_HOMING
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // MOD_ROCKET_HOMING_SPLASH
+ { 1.0f, 0.4f, 0.0f, 1.0f }, // MOD_THERMAL
+ { 1.0f, 0.4f, 0.0f, 1.0f }, // MOD_THERMAL_SPLASH
+ { 1.0f, 1.0f, 0.4f, 1.0f }, // MOD_TRIP_MINE_SPLASH
+ { 1.0f, 1.0f, 0.4f, 1.0f }, // MOD_TIMED_MINE_SPLASH
+ { 1.0f, 0.4f, 0.0f, 1.0f }, // MOD_DET_PACK_SPLASH
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // MOD_VEHICLE
+ { 1.0f, 0.0f, 1.0f, 1.0f }, // MOD_CONC
+ { 1.0f, 0.0f, 1.0f, 1.0f }, // MOD_CONC_ALT
+ { 1.0f, 0.4f, 0.0f, 1.0f }, // MOD_FORCE_DARK
+ { 1.0f, 1.0f, 1.0f, 1.0f }, // MOD_SENTRY
+ { 0.0f, 0.0f, 1.0f, 1.0f }, // MOD_WATER
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // MOD_SLIME
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // MOD_LAVA
+ { 0.0f, 0.0f, 0.0f, 1.0f }, // MOD_CRUSH
+ { 0.4f, 0.2f, 0.3f, 1.0f }, // MOD_TELEFRAG
+ { 1.0f, 1.0f, 0.6f, 1.0f }, // MOD_FALLING
+ { 0.5f, 0.2f, 0.7f, 1.0f }, // MOD_SUICIDE
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // MOD_TARGET_LASER
+ { 1.0f, 1.0f, 0.6f, 1.0f }, // MOD_TRIGGER_HURT
+ { 1.0f, 1.0f, 1.0f, 1.0f } // MOD_TEAM_CHANGE
+};
+
+const char *hudModIcons[ MOD_MAX ] = {
+ "hud/mod/generic", // MOD_UNKNOWN
+ "hud/mod/stun", // MOD_STUN_BATON
+ "hud/mod/melee", // MOD_MELEE
+ "hud/mod/saber", // MOD_SABER
+ "hud/mod/pistol", // MOD_BRYAR_PISTOL
+ "hud/mod/pistol", // MOD_BRYAR_PISTOL_ALT
+ "hud/mod/rifle", // MOD_BLASTER
+ "hud/mod/rifle_alt", // MOD_TURBLAST
+ "hud/mod/disruptor", // MOD_DISRUPTOR
+ "hud/mod/disruptor", // MOD_DISRUPTOR_SPLASH
+ "hud/mod/disruptor_alt", // MOD_DISRUPTOR_SNIPER
+ "hud/mod/bowcaster", // MOD_BOWCASTER
+ "hud/mod/repeater", // MOD_REPEATER
+ "hud/mod/repeater_alt", // MOD_REPEATER_ALT
+ "hud/mod/repeater_alt", // MOD_REPEATER_ALT_SPLASH
+ "hud/mod/demp2", // MOD_DEMP2
+ "hud/mod/demp2_alt", // MOD_DEMP2_ALT
+ "hud/mod/flechette", // MOD_FLECHETTE
+ "hud/mod/flechette_alt", // MOD_FLECHETTE_ALT_SPLASH
+ "hud/mod/merrsonn", // MOD_ROCKET
+ "hud/mod/merrsonn_splash", // MOD_ROCKET_SPLASH
+ "hud/mod/merrsonn_alt", // MOD_ROCKET_HOMING
+ "hud/mod/merrsonn_alt", // MOD_ROCKET_HOMING_SPLASH
+ "hud/mod/thermal", // MOD_THERMAL
+ "hud/mod/thermal_alt", // MOD_THERMAL_SPLASH
+ "hud/mod/mine", // MOD_TRIP_MINE_SPLASH
+ "hud/mod/mine_alt", // MOD_TIMED_MINE_SPLASH
+ "hud/mod/detpack", // MOD_DET_PACK_SPLASH
+ "hud/mod/swoop", // MOD_VEHICLE
+ "hud/mod/concussion", // MOD_CONC
+ "hud/mod/concussion_alt", // MOD_CONC_ALT
+ "hud/mod/force", // MOD_FORCE_DARK
+ "hud/mod/portable_turret", // MOD_SENTRY
+ "hud/mod/water", // MOD_WATER
+ "hud/mod/ooze", // MOD_SLIME
+ "hud/mod/lava", // MOD_LAVA
+ "hud/mod/crushed", // MOD_CRUSH
+ "hud/mod/telefrag", // MOD_TELEFRAG
+ "hud/mod/fall", // MOD_FALLING
+ "hud/mod/generic", // MOD_SUICIDE
+ "hud/mod/generic", // MOD_TARGET_LASER
+ "hud/mod/generic", // MOD_TRIGGER_HURT
+ "hud/mod/generic", // MOD_TEAM_CHANGE
+};
+
+hudMedia_t hm;
+
+// get all the required assets
+void HUD_InitMedia( void ) {
+ int i;
+ for ( i = 0; i < MOD_MAX; i++ ) {
+ hm.modIcon[i] = trap->R_RegisterShaderNoMip( hudModIcons[i] );
+ }
+}
+
diff --git a/codemp/ui/ui_xdocs.h b/codemp/ui/ui_xdocs.h
index d943adccc8..e5f3895fed 100644
--- a/codemp/ui/ui_xdocs.h
+++ b/codemp/ui/ui_xdocs.h
@@ -444,6 +444,31 @@ XDOCS_CVAR_DEF("g_gametype", "Gametype that the server is currently on",
SETTING("9", "CTY")
)
+XDOCS_CVAR_DEF("cg_killfeed", "Draw a killfeed on the HUD",
+SETTING("0", "Disable the HUD killfeed") NL
+SETTING("1", "Draw killfeed HUD") NL
+SETTING("2", "Draw killfeed HUD + console death messages")
+)
+
+XDOCS_CVAR_DEF("cg_killfeedAlignment", "Align the killfeed",
+SETTING("0", "Align items to the right") NL
+SETTING("1", "Align items to the left") NL
+SETTING("2", "Align items to the center")
+)
+
+XDOCS_CVAR_DEF("cg_killfeedX", "Offset the killfeed's horizontal position from its current position",""
+)
+
+XDOCS_CVAR_DEF("cg_killfeedY", "Offset the killfeed's vertical position from its current position",""
+)
+
+XDOCS_CVAR_DEF("cg_killfeedIconSize", "Resize the killfeed",""
+)
+XDOCS_CVAR_DEF("cg_killfeedTextSize", "Resize the killfeed",""
+)
+XDOCS_CVAR_DEF("cg_killfeedColors", "Color the killfeed icons",""
+)
+
//Work from above this line
// ...