diff --git a/src/dehacked.c b/src/dehacked.c
index 6365453fe94a5f3725b75be5f99dc9f5fbd42b89..a6f3074ddbdbbffb1d2a211226087124f8c17d14 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -6519,16 +6519,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	// Audience Members
 	"S_RANDOMAUDIENCE",
-	"S_AUDIENCE_TOAD1",
-	"S_AUDIENCE_TOAD2",
-	"S_AUDIENCE_BOO1",
-	"S_AUDIENCE_BOO2",
-	"S_AUDIENCE_GMBA1",
-	"S_AUDIENCE_GMBA2",
-	"S_AUDIENCE_SHYG1",
-	"S_AUDIENCE_SHYG2",
-	"S_AUDIENCE_SNIF1",
-	"S_AUDIENCE_SNIF2",
+	"S_AUDIENCE_CHAO_CHEER1",
+	"S_AUDIENCE_CHAO_CHEER2",
+	"S_AUDIENCE_CHAO_WIN1",
+	"S_AUDIENCE_CHAO_WIN2",
+	"S_AUDIENCE_CHAO_LOSE",
 
 	"S_FANCHAR_KOTE",
 	"S_FANCHAR_RYAN",
diff --git a/src/info.c b/src/info.c
index e7c40cb94d7f98989e0add633565a494ff23854d..554f410abe601988d70e1962777b26adb1c255b0 100644
--- a/src/info.c
+++ b/src/info.c
@@ -2831,18 +2831,15 @@ state_t states[NUMSTATES] =
 	{SPR_POKE, 3,  2, {A_MoveAbsolute}, 180, 2, S_POKEY5}, // S_POKEY8
 	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL},               // S_POKEYIDLE
 
-	{SPR_NULL, 0,  1, {A_RandomStateRange}, S_AUDIENCE_TOAD1, S_AUDIENCE_SNIF1, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE
-
-	{SPR_AUDI, 0,  5, {NULL},       0, 0, S_AUDIENCE_TOAD2}, // S_AUDIENCE_TOAD1
-	{SPR_AUDI, 1, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_TOAD1}, // S_AUDIENCE_TOAD2
-	{SPR_AUDI, 2,  5, {NULL},       0, 0, S_AUDIENCE_BOO2},  // S_AUDIENCE_BOO1
-	{SPR_AUDI, 3, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_BOO1},  // S_AUDIENCE_BOO2
-	{SPR_AUDI, 4,  5, {NULL},       0, 0, S_AUDIENCE_GMBA2}, // S_AUDIENCE_GMBA1
-	{SPR_AUDI, 5, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_GMBA1}, // S_AUDIENCE_GMBA2
-	{SPR_AUDI, 6,  5, {NULL},       0, 0, S_AUDIENCE_SHYG2}, // S_AUDIENCE_SHYG1
-	{SPR_AUDI, 7, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_SHYG1}, // S_AUDIENCE_SHYG2
-	{SPR_AUDI, 8,  5, {NULL},       0, 0, S_AUDIENCE_SNIF2}, // S_AUDIENCE_SNIF1
-	{SPR_AUDI, 9, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_SNIF1}, // S_AUDIENCE_SNIF2
+	{SPR_NULL, 0,  1, {A_RandomStateRange}, S_AUDIENCE_CHAO_CHEER1, S_AUDIENCE_CHAO_CHEER2, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE
+
+	{SPR_AUDI, 0,  5, {NULL},       0, 0, S_AUDIENCE_CHAO_CHEER2}, // S_AUDIENCE_CHAO_CHEER1
+	{SPR_AUDI, 1, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_CHAO_CHEER1}, // S_AUDIENCE_CHAO_CHEER2
+
+	{SPR_AUDI, 2,  5, {NULL},       0, 0, S_AUDIENCE_CHAO_WIN2}, // S_AUDIENCE_CHAO_WIN1
+	{SPR_AUDI, 3, 25, {A_BunnyHop}, 10, 0, S_AUDIENCE_CHAO_WIN1}, // S_AUDIENCE_CHAO_WIN2
+
+	{SPR_AUDI, 4|FF_ANIMATE,  -1, {NULL},       1, 17, S_NULL}, // S_AUDIENCE_CHAO_LOSE
 
 	{SPR_AUDI, 10, -1, {NULL}, 0, 0, S_NULL}, // S_FANCHAR_KOTE
 	{SPR_AUDI, 11, -1, {NULL}, 0, 0, S_NULL}, // S_FANCHAR_RYAN
@@ -14691,7 +14688,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // xdeathstate
 		sfx_kc2e,       // deathsound
 		0,              // speed
-		16*FRACUNIT,    // radius
+		24*FRACUNIT,    // radius
 		32*FRACUNIT,    // height
 		0,              // display offset
 		100,            // mass
@@ -14772,7 +14769,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // xdeathstate
 		sfx_s3k5d,      // deathsound
 		64*FRACUNIT,    // speed
-		16*FRACUNIT,    // radius
+		24*FRACUNIT,    // radius
 		32*FRACUNIT,    // height
 		0,              // display offset
 		100,            // mass
@@ -15501,8 +15498,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
 		8,              // speed
-		16*FRACUNIT,    // radius
-		40*FRACUNIT,    // height
+		8*FRACUNIT,     // radius
+		20*FRACUNIT,    // height
 		0,              // display offset
 		100,            // mass
 		0,              // damage
diff --git a/src/info.h b/src/info.h
index 53b5809aaccce0db4535d1a1f260156b4b661344..c5f98983cefa5191ade8232c8e48574e6a7e9eb4 100644
--- a/src/info.h
+++ b/src/info.h
@@ -3366,16 +3366,11 @@ typedef enum state
 
 	// Audience Members
 	S_RANDOMAUDIENCE,
-	S_AUDIENCE_TOAD1,
-	S_AUDIENCE_TOAD2,
-	S_AUDIENCE_BOO1,
-	S_AUDIENCE_BOO2,
-	S_AUDIENCE_GMBA1,
-	S_AUDIENCE_GMBA2,
-	S_AUDIENCE_SHYG1,
-	S_AUDIENCE_SHYG2,
-	S_AUDIENCE_SNIF1,
-	S_AUDIENCE_SNIF2,
+	S_AUDIENCE_CHAO_CHEER1,
+	S_AUDIENCE_CHAO_CHEER2,
+	S_AUDIENCE_CHAO_WIN1,
+	S_AUDIENCE_CHAO_WIN2,
+	S_AUDIENCE_CHAO_LOSE,
 
 	S_FANCHAR_KOTE,
 	S_FANCHAR_RYAN,
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 59b5c6cffe94e9e27685b46b3f551462fac40ce4..6c946e097a6318724ac16e3f160e71823611bddb 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -8927,6 +8927,39 @@ void P_SceneryThinker(mobj_t *mobj)
 	}
 
 	P_CycleMobjState(mobj);
+
+	if (mobj->type != MT_RANDOMAUDIENCE)
+		return;
+
+	{
+		if (!mobj->colorized) // a fan of someone?
+			return;
+
+		if (mobj->threshold >= 0) // not already happy or sad?
+		{
+			if (!playeringame[mobj->threshold] || players[mobj->threshold].spectator) // focused on a valid player?
+				return;
+
+			if (!(players[mobj->threshold].exiting) && !(players[mobj->threshold].pflags & PF_TIMEOVER)) // not finished yet?
+				return;
+
+			if (K_IsPlayerLosing(&players[mobj->threshold]))
+				mobj->threshold = -2;
+			else
+			{
+				mobj->threshold = -1;
+				S_StartSound(mobj, sfx_chaooo);
+			}
+		}
+
+		if (mobj->threshold == -1)
+			mobj->angle += ANGLE_22h;
+
+		if (((statenum_t)(mobj->state-states) != S_AUDIENCE_CHAO_CHEER2) || (mobj->tics != states[S_AUDIENCE_CHAO_CHEER2].tics)) // not at the start of your cheer jump?
+			return;
+
+		P_SetMobjState(mobj, ((mobj->threshold == -1) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE));
+	}
 }
 
 //
@@ -9174,9 +9207,43 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			}
 			break;
 		case MT_BIGRING:
-			mobj->destscale = 3*FRACUNIT;
-			P_SetScale(mobj, 3*FRACUNIT);
+			P_SetScale(mobj, (mobj->destscale = 3*FRACUNIT));
+			break;
+		case MT_RANDOMAUDIENCE:
+		{
+			fixed_t randu = P_RandomFixed();
+			P_SetScale(mobj, (mobj->destscale <<= 1));
+			if (randu < (FRACUNIT/9)) // a fan of someone?
+			{
+				UINT8 i, pcount = 0;
+				UINT8 pnum[MAXPLAYERS];
+
+				for (i = 0; i < MAXPLAYERS; i++)
+				{
+					if (!playeringame[i])
+						continue;
+					pnum[pcount] = i;
+					pcount++;
+				}
+
+				if (pcount)
+				{
+					mobj->threshold = pnum[P_RandomKey(pcount)];
+					mobj->color = players[mobj->threshold].skincolor;
+					mobj->colorized = true;
+					break;
+				}
+			}
+
+			if (randu > (FRACUNIT/2))
+			{
+				mobj->color = P_RandomKey(MAXSKINCOLORS-1)+1;
+				break;
+			}
+
+			mobj->color = SKINCOLOR_AQUA;
 			break;
+		}
 		default:
 			break;
 	}
diff --git a/src/sounds.c b/src/sounds.c
index 7c69eed7b6d877ccab9243f94e465986c41f4e49..938f35ea48a79ed6f7f2382617968002efa9b80d 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -813,6 +813,7 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"hogbom", false, 110,  8, -1, NULL, 0,        -1,  -1, LUMPERROR},
   {"ddash",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR},
   {"mcitm1", false, 110,  8, -1, NULL, 0,        -1,  -1, LUMPERROR},
+  {"chaooo", false, 110, 24, -1, NULL, 0,        -1,  -1, LUMPERROR},
   {"dbgsal", false, 110,  8, -1, NULL, 0,        -1,  -1, LUMPERROR},
 
   // SRB2kart - Skin sounds
diff --git a/src/sounds.h b/src/sounds.h
index 13669e3a83186c748ee78ee7d16d77d143f3b9c5..9aaaf2817b5900130966db1669dbbeee16a14357 100644
--- a/src/sounds.h
+++ b/src/sounds.h
@@ -885,6 +885,7 @@ typedef enum
 	sfx_hogbom,
 	sfx_ddash,
 	sfx_mcitm1,
+	sfx_chaooo,
 	sfx_dbgsal,
 
 	sfx_kwin,