summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2020-03-29 19:59:19 +0200
committerPaweł Redman <pawel.redman@gmail.com>2020-03-29 20:07:29 +0200
commitcad9e7c0e6bb22a945273ab6a39601db86d7db20 (patch)
tree947c5dc828da424df1de90a71ae845599f7de92b /src
parent0e6b1bc4a15f598d5eab507cbbe0f11410d5df1f (diff)
Implement coronavirus
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_event.c8
-rw-r--r--src/cgame/cg_local.h3
-rw-r--r--src/cgame/cg_main.c3
-rw-r--r--src/game/bg_public.h8
-rw-r--r--src/game/g_active.c156
-rw-r--r--src/game/g_client.c10
-rw-r--r--src/game/g_combat.c5
-rw-r--r--src/game/g_local.h14
8 files changed, 203 insertions, 4 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 07bcea9..c06a05c 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -132,6 +132,9 @@ static void CG_Obituary( entityState_t *ent )
case MOD_SWARM:
message = "was hunted down by the swarm";
break;
+ case MOD_CORONAVIRUS:
+ message = "died of viral lung infection";
+ break;
default:
message = NULL;
break;
@@ -658,6 +661,11 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
break;
+ case EV_COUGH:
+ DEBUGNAME( "EV_COUGH" );
+ trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.coughingSounds[ rand ( ) % NUM_COUGHING_SOUNDS ] );
+ break;
+
//
// weapon events
//
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index e68e94b..7618118 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1146,6 +1146,7 @@ typedef struct
int topSpeedTime;
} cg_t;
+#define NUM_COUGHING_SOUNDS 5
// all of the model, shader, and sound references that are
// loaded at gamestate time are stored in cgMedia_t
@@ -1277,6 +1278,8 @@ typedef struct
qhandle_t buildWeaponTimerPie[ 8 ];
qhandle_t upgradeClassIconShader;
+
+ sfxHandle_t coughingSounds[ NUM_COUGHING_SOUNDS ];
} cgMedia_t;
typedef struct
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 89a4c5c..24a82c2 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -955,6 +955,9 @@ static void CG_RegisterSounds( void )
cgs.media.buildableRepairedSound = trap_S_RegisterSound( "sound/buildables/human/repaired.wav", qfalse );
cgs.media.lCannonWarningSound = trap_S_RegisterSound( "models/weapons/lcannon/warning.wav", qfalse );
+
+ for( i = 0; i < NUM_COUGHING_SOUNDS; i++ )
+ cgs.media.coughingSounds[ i ] = trap_S_RegisterSound( va( "sound/player/cough%d.wav", i ), qfalse );
}
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 69967a1..b04b681 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -579,7 +579,9 @@ typedef enum
EV_DCC_ATTACK, //TA: dcc under attack
- EV_RPTUSE_SOUND //TA: trigger a sound
+ EV_RPTUSE_SOUND, //TA: trigger a sound
+
+ EV_COUGH
} entity_event_t;
typedef enum
@@ -894,7 +896,9 @@ typedef enum
MOD_ASPAWN,
MOD_ATUBE,
MOD_OVERMIND,
- MOD_SLAP
+ MOD_SLAP,
+
+ MOD_CORONAVIRUS
} meansOfDeath_t;
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 1dd27f4..528b927 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -73,7 +73,8 @@ void P_DamageFeedback( gentity_t *player )
if( ( level.time > player->pain_debounce_time ) && !( player->flags & FL_GODMODE ) )
{
player->pain_debounce_time = level.time + 700;
- G_AddEvent( player, EV_PAIN, player->health > 255 ? 255 : player->health );
+ if( player->lastDamageMOD != MOD_CORONAVIRUS )
+ G_AddEvent( player, EV_PAIN, player->health > 255 ? 255 : player->health );
client->ps.damageEvent++;
}
@@ -563,6 +564,157 @@ qboolean ClientInactivityTimer( gclient_t *client )
/*
==================
+G_ContractCoronavirus
+
+Called once per player when contracting the virus.
+There's a chance this is called at spawn.
+==================
+*/
+
+void G_ContractCoronavirus( gentity_t *ent )
+{
+ float rng;
+
+ rng = random( );
+
+ if ( rng < 0.3f )
+ ent->client->covidKind = COVID_ASYMPTOMATIC;
+ else if ( rng < 0.5f ) // 20% chance
+ ent->client->covidKind = COVID_SEVERE;
+ else
+ ent->client->covidKind = COVID_MODERATE;
+
+ trap_SendServerCommand( (int)( ent - g_entities ),
+ va("print \"^1COVID: ^7You contracted COVID of kind ^1%d^7.\n\"", ent->client->covidKind ) );
+}
+
+
+/*
+==================
+G_Coronavirus
+
+Runs every second, spreads the disease and causes symptoms.
+==================
+*/
+
+#define COVID_RANGE 300.0f
+#define COVID_INCUBATION_PERIOD 60.0f
+#define COVID_AVERAGE_LENGTH 240.0f
+
+void G_Coronavirus( gentity_t *ent )
+{
+ int entityList[ MAX_GENTITIES ];
+ vec3_t range = { COVID_RANGE, COVID_RANGE, COVID_RANGE };
+ vec3_t mins, maxs;
+ int i, num;
+ gclient_t *client = ent->client;
+
+ if( client->covidKind == COVID_NONE
+ || client->covidKind == COVID_RECOVERED )
+ return;
+
+ VectorAdd( client->ps.origin, range, maxs );
+ VectorSubtract( client->ps.origin, range, mins );
+
+ // Infect nearby players
+
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ gentity_t *target;
+ trace_t tr;
+ float chance = 0.001f; // to spread the disease
+ float distance;
+
+ target = g_entities + entityList[ i ];
+
+ if( !target->client || target->health < 0 )
+ continue;
+
+ if( target->client->covidKind != COVID_NONE )
+ continue;
+
+ trap_Trace( &tr, ent->s.origin, NULL, NULL, target->s.origin, target->s.number, MASK_SHOT );
+ if( tr.entityNum == ENTITYNUM_WORLD )
+ continue;
+
+ if( client->pers.teamSelection == target->client->pers.teamSelection )
+ chance *= 10.0f;
+
+ if( BG_InventoryContainsUpgrade( UP_HELMET, target->client->ps.stats ) )
+ chance /= 2.0f;
+
+ if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, target->client->ps.stats ) )
+ chance /= 8.0f;
+
+ distance = Distance(ent->s.origin, target->s.origin);
+
+ if( distance < COVID_RANGE / 10.0f )
+ chance *= 100.0f;
+ else if( distance < COVID_RANGE / 5.0f )
+ chance *= 20.0f;
+ else if( distance < COVID_RANGE / 3.0f )
+ chance *= 5.0f;
+ else if( distance < COVID_RANGE / 2.0f )
+ chance *= 2.0f;
+
+ trap_SendServerCommand( (int)( ent - g_entities ), va( "print \"^1COVID:^7 Chance to infect %s^7 is ^1%f^7\n\"",
+ target->client->pers.netname, chance ) );
+
+ if( random( ) < chance )
+ {
+ trap_SendServerCommand( (int)( ent - g_entities ), va( "print \"^1COVID:^7 You spread the virus.\n\"" ) );
+ G_ContractCoronavirus( target );
+ }
+ }
+
+ // Progression of the disease
+
+ client->covidProgress += 2.0f * random( ) / COVID_AVERAGE_LENGTH;
+ if( client->covidProgress > COVID_INCUBATION_PERIOD / COVID_AVERAGE_LENGTH )
+ {
+ float factor;
+
+ factor = 1 - 2 * COVID_INCUBATION_PERIOD / COVID_AVERAGE_LENGTH / 3 - client->covidProgress;
+ client->covidSeverity += 0.4f * factor * client->covidSeverity + 0.01f * factor;
+ }
+
+ if( client->covidKind == COVID_ASYMPTOMATIC )
+ client->covidSeverity *= 0.8f;
+ else if( client->covidKind == COVID_MODERATE )
+ client->covidSeverity *= 0.91f;
+ else
+ client->covidSeverity *= 0.935f;
+
+ if( client->covidProgress > 0.75f && client->covidSeverity < 0.01f )
+ {
+ client->covidKind = COVID_RECOVERED;
+ return;
+ }
+
+ // Symptoms
+
+ if( random( ) < client->covidSeverity / 4.0f )
+ {
+ G_AddEvent( ent, EV_COUGH, 0 );
+ }
+
+ client->covidDamage += client->covidSeverity;
+ if( client->covidDamage > 1.0f )
+ {
+ int damage;
+
+ damage = floor( client->covidDamage );
+ client->covidDamage -= damage;
+ G_Damage( ent, NULL, NULL, NULL, NULL, damage, DAMAGE_NO_PROTECTION, MOD_CORONAVIRUS );
+ }
+
+ trap_SendServerCommand( (int)( ent - g_entities ), va( "print \"^1COVID^7: Kind=^1%d^7, progress=^1%f^7, severity=^1%f^7.\n\"",
+ client->covidKind, client->covidProgress, client->covidSeverity) );
+}
+
+/*
+==================
ClientTimerActions
Actions that happen once a second
@@ -967,6 +1119,8 @@ void ClientTimerActions( gentity_t *ent, int msec )
}
}
}
+
+ G_Coronavirus( ent );
}
while( client->time10000 >= 10000 )
diff --git a/src/game/g_client.c b/src/game/g_client.c
index d204831..9f6710c 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1907,6 +1907,16 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
ent->client->ps.stats[ STAT_STATE ] = 0;
VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f );
+ client->covidKind = COVID_NONE;
+ client->covidProgress = 0.0f;
+ client->covidSeverity = 0.0f;
+ client->covidDamage = 0.0f;
+
+ // 1 in 10 chance they spawn sick
+ //if( rand( ) % 10 == 0 )
+ if( client->pers.classSelection != PCL_NONE )
+ G_ContractCoronavirus( ent );
+
// health will count down towards max_health
ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25;
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index aef76d1..5b4dac6 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -118,7 +118,9 @@ char *modNames[ ] =
"MOD_ASPAWN",
"MOD_ATUBE",
"MOD_OVERMIND",
- "MOD_SLAP"
+ "MOD_SLAP",
+
+ "MOD_CORONAVIRUS"
};
/*
@@ -1486,6 +1488,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
targ->client->ps.stats[ STAT_HEALTH ] = targ->health;
targ->lastDamageTime = level.time;
+ targ->lastDamageMOD = mod;
//TA: add to the attackers "account" on the target
if( targ->client && attacker->client )
diff --git a/src/game/g_local.h b/src/game/g_local.h
index baf69ee..68c1ac8 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -256,6 +256,7 @@ struct gentity_s
int suicideTime; // when the client will suicide
int lastDamageTime;
+ int lastDamageMOD;
int bdnumb; // buildlog entry ID
@@ -469,6 +470,14 @@ typedef struct {
float rangeBoost;
} adminRangeBoosts_t;
+enum {
+ COVID_NONE,
+ COVID_ASYMPTOMATIC,
+ COVID_MODERATE,
+ COVID_SEVERE,
+ COVID_RECOVERED
+};
+
// this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess'
struct gclient_s
@@ -570,6 +579,10 @@ struct gclient_s
adminRangeBoosts_t newRange;
+ int covidKind;
+ float covidProgress;
+ float covidSeverity;
+ float covidDamage;
};
@@ -1171,6 +1184,7 @@ void G_UnlaggedClear( gentity_t *ent );
void G_UnlaggedCalc( int time, gentity_t *skipEnt );
void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range );
void G_UnlaggedOff( void );
+void G_ContractCoronavirus( gentity_t *ent );
void ClientThink( int clientNum );
void ClientEndFrame( gentity_t *ent );
void G_RunClient( gentity_t *ent );