summaryrefslogtreecommitdiff
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:09:17 +0200
commitd9e9bb2d95483cbf2ca5d6cf5ac7b9f490d40204 (patch)
treec71483e197da36ebf8b11fec3e05df5608c7dc78
parent36ebcd1cc0933ee0bfe9f6ac15879286d3199046 (diff)
Implement coronavirus
-rw-r--r--sound/player/cough0.wavbin0 -> 66692 bytes
-rw-r--r--sound/player/cough1.wavbin0 -> 71250 bytes
-rw-r--r--sound/player/cough2.wavbin0 -> 35824 bytes
-rw-r--r--sound/player/cough3.wavbin0 -> 55062 bytes
-rw-r--r--sound/player/cough4.wavbin0 -> 41476 bytes
-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
13 files changed, 203 insertions, 4 deletions
diff --git a/sound/player/cough0.wav b/sound/player/cough0.wav
new file mode 100644
index 0000000..0150d90
--- /dev/null
+++ b/sound/player/cough0.wav
Binary files differ
diff --git a/sound/player/cough1.wav b/sound/player/cough1.wav
new file mode 100644
index 0000000..dc2e2ba
--- /dev/null
+++ b/sound/player/cough1.wav
Binary files differ
diff --git a/sound/player/cough2.wav b/sound/player/cough2.wav
new file mode 100644
index 0000000..4578b47
--- /dev/null
+++ b/sound/player/cough2.wav
Binary files differ
diff --git a/sound/player/cough3.wav b/sound/player/cough3.wav
new file mode 100644
index 0000000..d767fb7
--- /dev/null
+++ b/sound/player/cough3.wav
Binary files differ
diff --git a/sound/player/cough4.wav b/sound/player/cough4.wav
new file mode 100644
index 0000000..803aabc
--- /dev/null
+++ b/sound/player/cough4.wav
Binary files differ
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 83c3162..f35c438 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1142,6 +1142,7 @@ typedef struct
int ping;
} 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
@@ -1273,6 +1274,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 c2e55b8..45e2506 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -953,6 +953,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 1a67020..4059259 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
@@ -970,6 +1122,8 @@ void ClientTimerActions( gentity_t *ent, int msec )
if ( client->man_bad > 0 )
client->man_bad--;
+
+ 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 4d5d3d3..4df883c 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"
};
/*
@@ -1488,6 +1490,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 1720c4c..a088551 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
@@ -571,6 +580,10 @@ struct gclient_s
adminRangeBoosts_t newRange;
int man_bad;
+ int covidKind;
+ float covidProgress;
+ float covidSeverity;
+ float covidDamage;
};
@@ -1172,6 +1185,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 );