diff --git a/src/game/g_items.c b/src/game/g_items.c index 07495d6d3..9ebeef13b 100644 --- a/src/game/g_items.c +++ b/src/game/g_items.c @@ -591,11 +591,22 @@ int Pickup_Weapon(gentity_t *ent, gentity_t *other) */ int Pickup_Health(gentity_t *ent, gentity_t *other) { + int amount = ent->item->quantity; + if (ent->parent && ent->parent->client) { other->client->pers.lasthealth_client = ent->parent->s.clientNum; } + // Calculate health amount picked up + // current + amount > max ? + if (other->health + amount > other->client->ps.stats[STAT_MAX_HEALTH]) + { + // amount = max - current + amount = other->client->ps.stats[STAT_MAX_HEALTH] - other->health; + } + other->health += amount; + // if medic isn't giving ammo to self or the enemy, give him some props if (ent->parent && ent->parent->client && ent->parent->client != other->client && other->client->sess.sessionTeam == ent->parent->client->sess.sessionTeam) { @@ -603,11 +614,7 @@ int Pickup_Health(gentity_t *ent, gentity_t *other) G_DebugAddSkillPoints(ent->parent, SK_FIRST_AID, 1.f, "health pack picked up"); } - other->health += ent->item->quantity; - if (other->health > other->client->ps.stats[STAT_MAX_HEALTH]) - { - other->health = other->client->ps.stats[STAT_MAX_HEALTH]; - } + G_addStatsMedicHealth(other, ent->parent, amount); other->client->ps.stats[STAT_HEALTH] = other->health; #ifdef FEATURE_OMNIBOT diff --git a/src/game/g_local.h b/src/game/g_local.h index 10c0dcd25..4cae12705 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -666,6 +666,12 @@ typedef struct int damage_received; int team_damage_given; int team_damage_received; + int team_health_given; + int team_health_received; + int enemy_health_given; + int enemy_health_received; + int team_revive_given; + int team_revive_received; int time_axis; int time_allies; int time_played; @@ -2482,6 +2488,8 @@ qboolean G_isValidConfig(gentity_t *ent, const char *configname); void G_ReloadConfig(void); // g_match.c +void G_addStatsMedicRevive(gentity_t *target, gentity_t *source); +void G_addStatsMedicHealth(gentity_t *target, gentity_t *source, int value); void G_addStats(gentity_t *targ, gentity_t *attacker, int damage, meansOfDeath_t mod); void G_addStatsHeadShot(gentity_t *attacker, meansOfDeath_t mod); int G_checkServerToggle(vmCvar_t *cv); diff --git a/src/game/g_lua.c b/src/game/g_lua.c index 76e54e84b..18c88a07c 100644 --- a/src/game/g_lua.c +++ b/src/game/g_lua.c @@ -1037,6 +1037,12 @@ static const gentity_field_t gclient_fields[] = _et_gclient_addfield(sess.damage_received, FIELD_INT, 0), _et_gclient_addfield(sess.team_damage_given, FIELD_INT, 0), _et_gclient_addfield(sess.team_damage_received, FIELD_INT, 0), + _et_gclient_addfield(sess.team_health_given, FIELD_INT, 0), + _et_gclient_addfield(sess.team_health_received, FIELD_INT, 0), + _et_gclient_addfield(sess.enemy_health_given, FIELD_INT, 0), + _et_gclient_addfield(sess.enemy_health_received, FIELD_INT, 0), + _et_gclient_addfield(sess.team_revive_given, FIELD_INT, 0), + _et_gclient_addfield(sess.team_revive_received, FIELD_INT, 0), _et_gclient_addfield(sess.time_axis, FIELD_INT, FIELD_FLAG_READONLY), _et_gclient_addfield(sess.time_allies, FIELD_INT, FIELD_FLAG_READONLY), _et_gclient_addfield(sess.time_played, FIELD_INT, FIELD_FLAG_READONLY), diff --git a/src/game/g_match.c b/src/game/g_match.c index 9c686c68b..820abe13e 100644 --- a/src/game/g_match.c +++ b/src/game/g_match.c @@ -263,6 +263,60 @@ void G_spawnPrintf(int print_type, int print_time, gentity_t *owner) ent->think = G_delayPrint; } +/** + * @brief Adds revive stats to the session + * @param[in,out] target client who got revived + * @param[in,out] source client who revived target + */ +void G_addStatsMedicRevive(gentity_t *target, gentity_t *source) +{ +#ifndef DEBUG_STATS + if (g_gamestate.integer != GS_PLAYING) + { + return; + } +#endif + if (!source || !source->client) + { + return; + } + + source->client->sess.team_revive_given++; + target->client->sess.team_revive_received++; +} + +/** + * @brief Adds amount healing done by medics, from medkits and revives + * @param[in,out] target client who received the health + * @param[in,out] source client who gave the health + * @param[in] value amount of health points + */ +void G_addStatsMedicHealth(gentity_t *target, gentity_t *source, int value) +{ +#ifndef DEBUG_STATS + if (g_gamestate.integer != GS_PLAYING) + { + return; + } +#endif + if (!source || !source->client) + { + return; + } + + // check if target is from source's team + if (source->client->sess.sessionTeam == target->client->sess.sessionTeam) + { + source->client->sess.team_health_given += value; + target->client->sess.team_health_received += value; + } + else + { + source->client->sess.enemy_health_given += value; + target->client->sess.enemy_health_received += value; + } +} + /** * @brief G_addStats * @param[in,out] targ @@ -479,6 +533,13 @@ void G_createStatsJson(gentity_t *ent, void *target) cJSON_AddNumberToObject(tmp2, "self_kills", ent->client->sess.self_kills); cJSON_AddNumberToObject(tmp2, "team_kills", ent->client->sess.team_kills); cJSON_AddNumberToObject(tmp2, "team_gibs", ent->client->sess.team_gibs); + cJSON_AddNumberToObject(tmp2, "team_health_given", ent->client->sess.team_health_given); + cJSON_AddNumberToObject(tmp2, "team_health_received", ent->client->sess.team_health_received); + cJSON_AddNumberToObject(tmp2, "enemy_health_given", ent->client->sess.enemy_health_given); + cJSON_AddNumberToObject(tmp2, "enemy_health_received", ent->client->sess.enemy_health_received); + cJSON_AddNumberToObject(tmp2, "team_revive_given", ent->client->sess.team_revive_given); + cJSON_AddNumberToObject(tmp2, "team_revive_received", ent->client->sess.team_revive_received); + cJSON_AddNumberToObject(tmp2, "play_time", (ent->client->sess.time_axis + ent->client->sess.time_allies) == 0 ? 0 : 100.0 * ent->client->sess.time_played / (ent->client->sess.time_axis + ent->client->sess.time_allies)); } @@ -681,6 +742,13 @@ void G_deleteStats(int nClient) cl->sess.time_allies = 0; cl->sess.time_played = 0; + cl->sess.team_health_given = 0; + cl->sess.team_health_received = 0; + cl->sess.enemy_health_given = 0; + cl->sess.enemy_health_received = 0; + cl->sess.team_revive_given = 0; + cl->sess.team_revive_received = 0; + #ifdef FEATURE_RATING // skill rating cl->sess.mu = MU; @@ -753,6 +821,13 @@ void G_parseStatsJson(void *object) cl->sess.damage_received = Q_ReadIntValueJson(tmp, "damage_received"); cl->sess.team_damage_given = Q_ReadIntValueJson(tmp, "team_damage_given"); cl->sess.team_damage_received = Q_ReadIntValueJson(tmp, "team_damage_received"); + + cl->sess.team_health_given = Q_ReadIntValueJson(tmp, "team_health_given"); + cl->sess.team_health_received = Q_ReadIntValueJson(tmp, "team_health_received"); + cl->sess.enemy_health_given = Q_ReadIntValueJson(tmp, "enemy_health_given"); + cl->sess.enemy_health_received = Q_ReadIntValueJson(tmp, "enemy_health_received"); + cl->sess.team_revive_given = Q_ReadIntValueJson(tmp, "team_revive_given"); + cl->sess.team_revive_received = Q_ReadIntValueJson(tmp, "team_revive_received"); } else { @@ -770,7 +845,7 @@ void G_parseStatsJson(void *object) void G_printMatchInfo(gentity_t *ent) { int i, j, cnt = 0, eff, time_eff; - int tot_timex, tot_timel, tot_timep, tot_kills, tot_deaths, tot_gibs, tot_sk, tot_tk, tot_tg, tot_dg, tot_dr, tot_tdg, tot_tdr, tot_xp; + int tot_timex, tot_timel, tot_timep, tot_kills, tot_deaths, tot_gibs, tot_sk, tot_tk, tot_tg, tot_dg, tot_dr, tot_tdg, tot_tdr, tot_xp, tot_rg, tot_rr, tot_thd, tot_thr, tot_ehd, tot_ehr; gclient_t *cl; gentity_t *cl_ent; char *ref; @@ -798,14 +873,20 @@ void G_printMatchInfo(gentity_t *ent) tot_tdg = 0; tot_tdr = 0; tot_xp = 0; + tot_rg = 0; // Revives given + tot_rr = 0; // revives done + tot_thd = 0; // team healing done + tot_thr = 0; // team healing rec + tot_ehd = 0; // enem healing done + tot_ehr = 0; // enem healing rec CP("sc \"\n\""); #ifdef FEATURE_RATING - CP("sc \"^7GUID TEAM Player ^1 TmX^$ TmL^7 TmP^7 Kll Dth Gib SK TK TG^7 Eff^2 DG^1 DR^6 TDG^$ TDR^3 Score^8 Rating^5 Delta\n\""); - CP("sc \"^7------------------------------------------------------------------------------------------------------------------------\n\""); + CP("sc \"^7GUID TEAM Player ^1 TmX^$ TmL^7 TmP^7 Kll Dth Gib SK TK TG RG RR^7 Eff^2 DG^1 DR^6 TDG^$ TDR^2 THG^$ THR^1 EHG^2 EHR^3 Score^8 Rating^5 Delta\n\""); + CP("sc \"^7--------------------------------------------------------------------------------------------------------------------------------------------------------\n\""); #else - CP("sc \"^7GUID TEAM Player ^1 TmX^$ TmL^7 TmP^7 Kll Dth Gib SK TK TG^7 Eff^2 DG^1 DR^6 TDG^$ TDR^3 Score\n\""); - CP("sc \"^7---------------------------------------------------------------------------------------------------------\n\""); + CP("sc \"^7GUID TEAM Player ^1 TmX^$ TmL^7 TmP^7 Kll Dth Gib SK TK TG RG RR^7 Eff^2 DG^1 DR^6 TDG^$ TDR^2 THG^$ THR^1 EHG^2 EHR^3 Score\n\""); + CP("sc \"^7-----------------------------------------------------------------------------------------------------------------------------------------\n\""); #endif for (j = 0; j < level.numConnectedClients; j++) @@ -846,6 +927,14 @@ void G_printMatchInfo(gentity_t *ent) tot_dr += cl->sess.damage_received; tot_tdg += cl->sess.team_damage_given; tot_tdr += cl->sess.team_damage_received; + + tot_rg += cl->sess.team_revive_given; + tot_rr += cl->sess.team_revive_received; + tot_thd += cl->sess.team_health_given; + tot_thr += cl->sess.team_health_received; + tot_ehd += cl->sess.enemy_health_given; + tot_ehr += cl->sess.enemy_health_received; + tot_xp += (g_gametype.integer == GT_WOLF_LMS || g_gametype.integer == GT_WOLF_STOPWATCH) ? cl->ps.persistant[PERS_SCORE] : cl->ps.stats[STAT_XP]; eff = (cl->sess.deaths + cl->sess.kills == 0) ? 0 : 100 * cl->sess.kills / (cl->sess.deaths + cl->sess.kills); @@ -866,9 +955,9 @@ void G_printMatchInfo(gentity_t *ent) cnt++; #ifdef FEATURE_RATING - trap_SendServerCommand(ent - g_entities, va("sc \"%-9s %-14s %s%-15s^1%4d^$%4d^7%s%4d^3%4d%4d%4d%4d%4d%4d%s%4d^2%6d^1%6d^6%5d^$%5d^3%7d^8%8.2f^5%+7.2f\n\"", + trap_SendServerCommand(ent - g_entities, va("sc \"%-9s %-14s %s%-15s^1%4d^$%4d^7%s%4d^3%4d%4d%4d%4d%4d%4d%4d%4d%s%4d^2%6d^1%6d^6%5d^$%5d^2%6d^$%6d^1%6d^2%6d^3%7d^8%8.2f^5%+7.2f\n\"", #else - trap_SendServerCommand(ent - g_entities, va("sc \"%-9s %-14s %s%-15s^1%4d^$%4d^7%s%4d^3%4d%4d%4d%4d%4d%4d%s%4d^2%6d^1%6d^6%5d^$%5d^3%7d\n\"", + trap_SendServerCommand(ent - g_entities, va("sc \"%-9s %-14s %s%-15s^1%4d^$%4d^7%s%4d^3%4d%4d%4d%4d%4d%4d%4d%4d%s%4d^2%6d^1%6d^6%5d^$%5d^2%6d^$%6d^1%6d^2%6d^3%7d\n\"", #endif guid, aTeams[i], @@ -884,12 +973,18 @@ void G_printMatchInfo(gentity_t *ent) cl->sess.self_kills, cl->sess.team_kills, cl->sess.team_gibs, + cl->sess.team_revive_given, + cl->sess.team_revive_received, ref, eff, cl->sess.damage_given, cl->sess.damage_received, cl->sess.team_damage_given, cl->sess.team_damage_received, + cl->sess.team_health_given, + cl->sess.team_health_received, + cl->sess.enemy_health_given, + cl->sess.enemy_health_received, (g_gametype.integer == GT_WOLF_LMS || g_gametype.integer == GT_WOLF_STOPWATCH) ? cl->ps.persistant[PERS_SCORE] : cl->ps.stats[STAT_XP] #ifdef FEATURE_RATING , @@ -908,11 +1003,11 @@ void G_printMatchInfo(gentity_t *ent) time_eff = (tot_timex + tot_timel == 0) ? 0 : 100 * tot_timep / (tot_timex + tot_timel); #ifdef FEATURE_RATING - CP("sc \"^7------------------------------------------------------------------------------------------------------------------------\n\""); + CP("sc \"^7--------------------------------------------------------------------------------------------------------------------------------------------------------\n\""); #else - CP("sc \"^7---------------------------------------------------------------------------------------------------------\n\""); + CP("sc \"^7-----------------------------------------------------------------------------------------------------------------------------------------\n\""); #endif - trap_SendServerCommand(ent - g_entities, va("sc \"%-9s %-14s ^5%-15s^1%4d^$%4d^5%4d%4d%4d%4d%4d%4d%4d^5%4d^2%6d^1%6d^6%5d^$%5d^3%7d\n\"", + trap_SendServerCommand(ent - g_entities, va("sc \"%-9s %-14s ^5%-15s^1%4d^$%4d^5%4d%4d%4d%4d%4d%4d%4d^5%4d%4d%4d^2%6d^1%6d^6%5d^$%5d^2%6d^$%6d^1%6d^2%6d^3%7d\n\"", "", aTeams[i], "Totals", @@ -925,11 +1020,17 @@ void G_printMatchInfo(gentity_t *ent) tot_sk, tot_tk, tot_tg, + tot_rg, + tot_rr, eff, tot_dg, tot_dr, tot_tdg, tot_tdr, + tot_thd, + tot_thr, + tot_ehd, + tot_ehr, tot_xp )); } diff --git a/src/game/g_session.c b/src/game/g_session.c index 8a50756cc..19d55188a 100644 --- a/src/game/g_session.c +++ b/src/game/g_session.c @@ -332,30 +332,35 @@ void G_ReadSessionData(gclient_t *client) root = Q_FSReadJsonFrom(fileName); - client->sess.sessionTeam = Q_ReadIntValueJson(root, "sessionTeam"); - client->sess.spectatorTime = Q_ReadIntValueJson(root, "spectatorTime"); - client->sess.spectatorState = Q_ReadIntValueJson(root, "spectatorState"); - client->sess.spectatorClient = Q_ReadIntValueJson(root, "spectatorClient"); - client->sess.playerType = Q_ReadIntValueJson(root, "playerType"); - client->sess.playerWeapon = Q_ReadIntValueJson(root, "playerWeapon"); - client->sess.playerWeapon2 = Q_ReadIntValueJson(root, "playerWeapon2"); - client->sess.latchPlayerType = Q_ReadIntValueJson(root, "latchPlayerType"); - client->sess.latchPlayerWeapon = Q_ReadIntValueJson(root, "latchPlayerWeapon"); - client->sess.latchPlayerWeapon2 = Q_ReadIntValueJson(root, "latchPlayerWeapon2"); - client->sess.referee = Q_ReadIntValueJson(root, "referee"); - client->sess.shoutcaster = Q_ReadIntValueJson(root, "shoutcaster"); - client->sess.spec_invite = Q_ReadIntValueJson(root, "spec_invite"); - client->sess.spec_team = Q_ReadIntValueJson(root, "spec_team"); - client->sess.kills = Q_ReadIntValueJson(root, "kills"); - client->sess.deaths = Q_ReadIntValueJson(root, "deaths"); - client->sess.gibs = Q_ReadIntValueJson(root, "gibs"); - client->sess.self_kills = Q_ReadIntValueJson(root, "self_kills"); - client->sess.team_kills = Q_ReadIntValueJson(root, "team_kills"); - client->sess.team_gibs = Q_ReadIntValueJson(root, "team_gibs"); - client->sess.time_axis = Q_ReadIntValueJson(root, "time_axis"); - client->sess.time_allies = Q_ReadIntValueJson(root, "time_allies"); - client->sess.time_played = Q_ReadIntValueJson(root, "time_played"); - + client->sess.sessionTeam = Q_ReadIntValueJson(root, "sessionTeam"); + client->sess.spectatorTime = Q_ReadIntValueJson(root, "spectatorTime"); + client->sess.spectatorState = Q_ReadIntValueJson(root, "spectatorState"); + client->sess.spectatorClient = Q_ReadIntValueJson(root, "spectatorClient"); + client->sess.playerType = Q_ReadIntValueJson(root, "playerType"); + client->sess.playerWeapon = Q_ReadIntValueJson(root, "playerWeapon"); + client->sess.playerWeapon2 = Q_ReadIntValueJson(root, "playerWeapon2"); + client->sess.latchPlayerType = Q_ReadIntValueJson(root, "latchPlayerType"); + client->sess.latchPlayerWeapon = Q_ReadIntValueJson(root, "latchPlayerWeapon"); + client->sess.latchPlayerWeapon2 = Q_ReadIntValueJson(root, "latchPlayerWeapon2"); + client->sess.referee = Q_ReadIntValueJson(root, "referee"); + client->sess.shoutcaster = Q_ReadIntValueJson(root, "shoutcaster"); + client->sess.spec_invite = Q_ReadIntValueJson(root, "spec_invite"); + client->sess.spec_team = Q_ReadIntValueJson(root, "spec_team"); + client->sess.kills = Q_ReadIntValueJson(root, "kills"); + client->sess.deaths = Q_ReadIntValueJson(root, "deaths"); + client->sess.gibs = Q_ReadIntValueJson(root, "gibs"); + client->sess.self_kills = Q_ReadIntValueJson(root, "self_kills"); + client->sess.team_kills = Q_ReadIntValueJson(root, "team_kills"); + client->sess.team_gibs = Q_ReadIntValueJson(root, "team_gibs"); + client->sess.time_axis = Q_ReadIntValueJson(root, "time_axis"); + client->sess.time_allies = Q_ReadIntValueJson(root, "time_allies"); + client->sess.time_played = Q_ReadIntValueJson(root, "time_played"); + client->sess.team_health_given = Q_ReadIntValueJson(root, "team_health_given"); + client->sess.team_health_received = Q_ReadIntValueJson(root, "team_health_received"); + client->sess.enemy_health_given = Q_ReadIntValueJson(root, "enemy_health_given"); + client->sess.enemy_health_received = Q_ReadIntValueJson(root, "enemy_health_received"); + client->sess.team_revive_given = Q_ReadIntValueJson(root, "team_revive_given"); + client->sess.team_revive_received = Q_ReadIntValueJson(root, "team_revive_received"); #ifdef FEATURE_RATING { cJSON *ratingObj = cJSON_GetObjectItem(root, "rating"); diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 04fd8d550..026b9d46d 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -380,6 +380,11 @@ void ReviveEntity(gentity_t *ent, gentity_t *traceEnt) traceEnt->client->ps.weapAnim = PM_IdleAnimForWeapon(traceEnt->client->ps.weapon); traceEnt->health = healamt; + + // set stats for revive event (revives and heal amount) + G_addStatsMedicRevive(traceEnt, ent); + G_addStatsMedicHealth(traceEnt, ent, healamt); + VectorCopy(org, traceEnt->s.origin); VectorCopy(org, traceEnt->r.currentOrigin); VectorCopy(org, traceEnt->client->ps.origin);