Barrels/Baskets
The Barrels and Baskets (shortened to just “barrels” when repetition gets tedious) are two visually distinct types of object that function identically. In their initial state, they sit on the ground and appear as static, motionless metallic drums or woven fabric squares. Each barrel releases a different predefined actor when destroyed, either as a result of the player pouncing on it or due to an explosion in close proximity. All of the barrels encountered in an unmodified game will release a prize of some sort, although unusual and unused barrel types do exist.
Harmful | no |
---|---|
Vulnerable (Pounces) | yes |
Pounces Required | 1 |
Pounce Points | 100 |
Vulnerable (Explosions) | yes |
Explosions Required | 1 |
Explosion Points | 1,600 |
Name Origin | Canonical; appears in the hint sheet text. |
Data Fields
data1
- The actor type that will be spawned when the barrel is destroyed. This actor should have its “always active” and “weighted” flags enabled to allow the actor to potentially spawn off the top edge of the scrolling game window and fall back down.
data2
- The sprite type that will be shown as shards when the barrel is destroyed. This sprite type is expected to have at least four frames available. This value should be
SPR_BARREL_SHARDS
orSPR_BASKET_SHARDS
.
Initial Values
Barrels
Actor Type | ACT_BARREL_POWER_UP (29) | ACT_BARREL_YEL_PEAR (35) | ACT_BARREL_ONION (37) | ACT_BARREL_BOMB (56) | ACT_BARREL_CABB_HARDER (100) | ACT_BARREL_BOTL_DRINK (142) | ACT_BARREL_HORN (117) | ACT_BARREL_RT_ORNAMENT (156) | ACT_BARREL_BLU_CRYSTAL (157) | ACT_BARREL_RED_CRYSTAL (158) | ACT_BARREL_GRN_EMERALD (173) | ACT_BARREL_CLR_DIAMOND (175) | ACT_BARREL_CYA_DIAMOND (193) | ACT_BARREL_RED_DIAMOND (195) | ACT_BARREL_GRY_OCTAHED (197) | ACT_BARREL_BLU_EMERALD (199) | ACT_BARREL_HEADPHONES (218) | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Sprite Type | SPR_BARREL | |||||||||||||||||
X Shift | 0 | |||||||||||||||||
Y Shift | 0 | |||||||||||||||||
Force Active | yes | |||||||||||||||||
Stay Active | no | |||||||||||||||||
Weighted | yes | |||||||||||||||||
Acrophile | no | yes | no | |||||||||||||||
Data 1 | ||||||||||||||||||
Data 2 | SPR_BARREL_SHARDS | |||||||||||||||||
Data 3 | 0 (not used) | |||||||||||||||||
Data 4 | 0 (not used) | |||||||||||||||||
Data 5 | 0 (not used) |
Note: The differences in the
acrophile
flag do not matter since barrels do not walk.
Baskets
Actor Type | ACT_BASKET_NULL (0) | ACT_BASKET_HAMBURGER (81) | ACT_BASKET_GRN_GOURD (52) | ACT_BASKET_POD (119) | ACT_BASKET_PEA_PILE (115) | ACT_BASKET_LUMPY_FRUIT (116) | ACT_BASKET_HEADDRESS (148) | ACT_BASKET_ROOT (167) | ACT_BASKET_RG_BERRIES (169) | ACT_BASKET_RED_GOURD (171) | ACT_BASKET_RED_LEAFY (224) | ACT_BASKET_BRN_PEAR (227) | ACT_BASKET_CANDY_CORN (230) | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Sprite Type | SPR_BASKET | ||||||||||||||||
X Shift | 0 | ||||||||||||||||
Y Shift | 0 | ||||||||||||||||
Force Active | yes | ||||||||||||||||
Stay Active | no | ||||||||||||||||
Weighted | yes | no | yes | ||||||||||||||
Acrophile | no | ||||||||||||||||
Data 1 | |||||||||||||||||
Data 2 | SPR_BASKET_SHARDS | ||||||||||||||||
Data 3 | 0 (not used) | ||||||||||||||||
Data 4 | 0 (not used) | ||||||||||||||||
Data 5 | 0 (not used) |
Note: The differences in the
weighted
flag could have a visible effect, in the case of e.g. a Basket (contains three-fingered yellow/cyan fruit) sitting on a moving platform – it would not descend along with the platform. This is a moot issue in practice since this actor type is unused.
Player Interaction
Inside the InteractPlayer()
function, this case occurs every time a barrel actor is processed:
case SPR_BASKET:
case SPR_BARREL:
if (act->hurtcooldown == 0 && TryPounce(5)) {
DestroyBarrel(index);
AddScore(100);
NewActor(ACT_SCORE_EFFECT_100, act->x, act->y);
return true;
}
return false;
This responds to actors having the SPR_BASKET
or SPR_BARREL
sprite types. If the barrel has a hurtcooldown
of zero, it is eligible to be pounced and TryPounce()
tests to see if the player is appropriately positioned to be pouncing on it at this time. A recoil value of 5 is imparted to the player if the pounce succeeds, then the if
’s body runs.
When a barrel is pounced, DestroyBarrel()
is called with index
(as passed into InteractPlayer()
) as the argument to destroy the barrel and spawn its contents into the game world. AddScore()
gives the player 100 points and NewActor()
spawns a Floating Score (ACT_SCORE_EFFECT_100
) at the barrel’s final x
/y
position to call attention to this.
InteractPlayer()
’s convention is to return true
in cases where the actor should not be drawn for this tick (here because it has been destroyed) and false
in the common case where nothing has changed with the actor’s state.
ActBarrel()
ActBarrel()
is the tick function for every barrel and basket actor. It takes the index
of the current actor in the actors array.
void ActBarrel(word index)
{
Actor *act = actors + index;
The passed index
is added to the actors[]
array, locating the Actor
structure for the barrel being processed. act
is the pointer to this actor.
if (IsNearExplosion(SPR_BARREL, 0, act->x, act->y)) {
DestroyBarrel(index);
AddScore(1600);
NewActor(ACT_SCORE_EFFECT_1600, act->x, act->y);
}
}
Barrels can be destroyed by explosions, and IsNearExplosion()
will return true if one is currently nearby. For the purposes of this test, the actual barrel/basket type is temporarily ignored and the intersection is tested as if every actor was showing frame zero of SPR_BARREL
. This is not a problem in the horizontal direction because barrel and basket sprites are both four tiles wide. Vertically, the barrels are one tile taller than the baskets – this could cause an explosion to register a hit to the top of a basket even though it visually misses it by one tile.
If an explosion is touching the barrel, DestroyBarrel()
is called with index
as the argument to destroy the barrel and spawn its contents into the game world. AddScore()
gives the player 1,600 points and NewActor()
spawns a Floating Score (ACT_SCORE_EFFECT_1600
) at the barrel’s final x
/y
position to call attention to this.
DestroyBarrel()
The DestroyBarrel()
function handles the animation, sound effects, and lifecycle management at the instant a barrel or basket is destroyed.
void DestroyBarrel(word index)
{
Actor *act = actors + index;
act->dead = true;
The passed index
is added to the actors[]
array, locating the Actor
structure for the barrel being processed. act
is the pointer to this actor.
Setting the barrel’s dead
to true effectively removes it from the map and from all subsequent processing. Its life has now ended.
NewShard(act->data2, 0, act->x - 1, act->y);
NewShard(act->data2, 1, act->x + 1, act->y - 1);
NewShard(act->data2, 2, act->x + 3, act->y);
NewShard(act->data2, 3, act->x + 2, act->y + 2);
Four shards are released around the barrel’s final x
/y
position with NewShard()
, using the value in data2
to select between barrel or basket shards as appropriate for the actor type. Frames 0–3 of these sprite types contain different “strips” of debris rather than anything that could be considered an animation.
if (GameRand() % 2 != 0) {
StartSound(SND_BARREL_DESTROY_1);
} else {
StartSound(SND_BARREL_DESTROY_2);
}
There are two sound effects, SND_BARREL_DESTROY_1
and SND_BARREL_DESTROY_2
, selected with 50/50 probability based on the GameRand()
result. Whichever sound effect is chosen is queued for playback with StartSound()
.
NewSpawner(act->data1, act->x + 1, act->y);
data1
is the actor type of the object that the barrel releases. NewSpawner()
begins spawning it into existence starting at the barrel’s final y
position and one tile to the right of x
. This perfectly centers any sprites that happen to be two tiles wide.
if (numBarrels == 1) {
NewActor(ACT_SPEECH_WOW_50K, playerX - 1, playerY - 5);
}
numBarrels--;
}
In the case where numBarrels
equals 1, this was the last remaining barrel and/or basket on the map. This is worthy of a score bonus, which is granted indirectly by inserting a “Speech Bubble: Wow! 50,000 points!” (ACT_SPEECH_WOW_50K
) actor via NewActor()
. This new actor is centered relative to the player, since this is a speech bubble coming out of them.
In all cases, numBarrels
is decremented to keep the count accurate to the remaining barrel population.