A_BubbleSpawn is an action used by the Air Bubble Patch that, if underwater, spawns a randomly sized bubble at the actor's location. Normally, the actor randomly chooses between spawning an Object of type MT_SMALLBUBBLE, an Object of type MT_MEDIUMBUBBLE, or spawning nothing at all otherwise – however, if the action is called within the first 8 tics of every third second of time passed in the level, an Object of type MT_EXTRALARGEBUBBLE (the large, breathable bubble) is spawned instead. Note that A_BubbleSpawn should not be called more frequently than every 8 tics, otherwise multiple MT_EXTRALARGEBUBBLE Objects can potentially be spawned within only a few tics of each other (given the 8 tic window they can spawn in every third second).
If the actor is not underwater when the action is called, the actor is given the MF2_DONTDRAW flag, becoming invisible, and will not spawn any bubbles; if the actor is underwater again the next time the action is called, the MF2_DONTDRAW flag is removed and the actor will continue spawning bubbles again. To save memory, bubbles are also not spawned if there is no player nearby: Var1 determines the distance in fracunits to search for players around the actor; if the actor cannot find any players within this distance, no bubbles will be spawned. This behavior is disabled if the actor has MF2_AMBUSH in its flags.
Bubble spawn chances
The exact chances of each type of bubble (or nothing) spawning are given below. Note that the result of a single P_RandomByte call (a number betwen 0 and 255 inclusive) is used by A_BubbleSpawn to determine what is spawned, except in the case of MT_EXTRALARGEBUBBLE.
Object type
Sprite
P_RandomByte results
Chance of occurring
MT_SMALLBUBBLE
129 to 255
127/256, or ~49.6%
MT_MEDIUMBUBBLE
97 to 127
31/256, or ~12.1%
Nothing
(None)
0 to 96, 128
98/256, or ~38.3%
MT_EXTRALARGEBUBBLE
N/A
100% if action called when leveltime % (3*TICRATE) < 8 0% otherwise
Code – A_BubbleSpawn
// Function: A_BubbleSpawn//// Description: Spawns a randomly sized bubble from the object's location. Only works underwater.//// var1 = Distance to look for players. If no player is in this distance, bubbles aren't spawned. (Ambush overrides)// var2 = unused//voidA_BubbleSpawn(mobj_t*actor){INT32i,locvar1=var1;UINT8prandom;mobj_t*bubble=NULL;#ifdef HAVE_BLUAif(LUA_CallAction("A_BubbleSpawn",actor))return;#endifif(!(actor->eflags&MFE_UNDERWATER)){// Don't draw or spawn bubbles above wateractor->flags2|=MF2_DONTDRAW;return;}actor->flags2&=~MF2_DONTDRAW;if(!(actor->flags2&MF2_AMBUSH)){// Quick! Look through players!// Don't spawn bubbles unless a player is relatively close by (var1).for(i=0;i<MAXPLAYERS;++i)if(playeringame[i]&&players[i].mo&&P_AproxDistance(actor->x-players[i].mo->x,actor->y-players[i].mo->y)<(locvar1<<FRACBITS))break;// Stop looking.if(i==MAXPLAYERS)return;// don't make bubble!}prandom=P_RandomByte();if(leveltime%(3*TICRATE)<8)bubble=P_SpawnMobj(actor->x,actor->y,actor->z+(actor->height/2),MT_EXTRALARGEBUBBLE);elseif(prandom>128)bubble=P_SpawnMobj(actor->x,actor->y,actor->z+(actor->height/2),MT_SMALLBUBBLE);elseif(prandom<128&&prandom>96)bubble=P_SpawnMobj(actor->x,actor->y,actor->z+(actor->height/2),MT_MEDIUMBUBBLE);if(bubble){bubble->destscale=actor->scale;P_SetScale(bubble,actor->scale);}}