void PSBTM(Object* self) { switch(self->routine) { case Routine_Init: self->routine = Routine_PrsStart; self->x = PSB_ScreenX; self->screenY = PSB_ScreenY; self->map = Map_PSB; self->gfx = GFX_PSB; if(self->frame >= Frame_SpriteLineLimiter) { self->routine = Routine_Exit; if(self->frame == Frame_TM) { self->gfx = GFX_TM; self->x = TM_ScreenX; self->screenY = TM_ScreenY; } break; } // fall through case Routine_PrsStart: AnimateSprite(self, Ani_PSBTM); break; case Routine_Exit: break; } DisplaySprite(self); }
void TitleSonic(Object* self) { switch(self->routine) { case Routine_Init: self->routine = Routine_Delay; self->x = TitleSonic_ScreenX; self->screenY = TitleSonic_ScreenY; self->map = Map_TitleSonic; self->gfx = GFX_TitleSonic; self->priority = 1; self->delayAni = 29; AnimateSprite(self, Ani_TitleSonic); // fall through case Routine_Delay: if(TimerNeg(self->delayAni)) { self->routine = Routine_Move; DisplaySprite(self); } break; case Routine_Move: self->obScreenY -= 8; if(self->screenY == (128 + 22)) self->routine = Routine_Animate; DisplaySprite(self); break; case Routine_Animate: AnimateSprite(self, Ani_TitleSonic); DisplaySprite(self); break; } }
/* * DrawAllUnits * * Draw all the units */ void DrawAllUnits (GdkPixmap *pixmap, GtkWidget *drawing_area) { /* * Move and display the hero */ ApplyFriction (); Move (hero); /* --- Keep him in-bounds. --- */ AdjustSpriteHeight (hero); DisplaySprite (drawing_area, sprite_ship, nShipAdjustment - (sprite_ship->width / 2), (int) hero->y - (sprite_ship->height / 2)); /* * Move and display everyone else */ DisplayOtherUnits (pixmap, drawing_area); }
void Splash(Object* self) { switch(self->routine) { case Routine_Init: self->routine = Routine_Main; self->map = Map_Splash; Obj_SetSomething(self); self->priority = 1; self->obActWid = 16; self->gfx = GFX_Splash; self->x = v_player->x; // fall through case Routine_Main: self->y = v_waterpos1; AnimateSprite(self, Ani_Splash) DisplaySprite(self); break; case Routine_Delete: DeleteObject(self); break; } }
/* * DisplayOtherUnits * * Display all the units on the screen. First, we need * to move each of the units to their new positions. * Some of this is done in the AI module. * */ void DisplayOtherUnits (GdkPixmap *pixmap, GtkWidget *drawing_area) { typUnit *unit; typUnit *unitHit; GList *node; int xPos; int xPosEnd; typSprite *sprite; /* --- Each unit in the list --- */ for (node = unitList; node; node = node->next) { /* --- Get the unit --- */ unit = (typUnit *) node->data; /* * --- Run the AI module on it to move it --- */ AIModule (unit); /* * If the unit was destroyed by the AI, * don't draw the unit. */ if (unit->bDestroy) { continue; } /* * If there's no sprite for the unit, * we can't draw it now, can we? */ sprite = GetSprite (unit); if (sprite == NULL) continue; /* --- Where on the screen is it going? --- */ xPos = UnitScreenX (unit); /* --- Make sure unit doesn't go out of bounds --- */ AdjustSpriteHeight (unit); /* --- Finally draw unit --- */ DisplaySprite (drawing_area, sprite, (int) (xPos - sprite[0].width / 2), (int) (unit->y - sprite[0].height / 2)); } /* * --- once everyone is painted, fire the lasers. */ for (node = unitList; node; node = node->next) { unit = (typUnit *) node->data; /* --- If this is a laser --- */ if (unit->type == LASER) { /* --- Get starting and ending positions --- */ xPos = ScreenX ((int) unit->x); xPosEnd = xPos + LASER_LENGTH * unit->direction; /* --- See if anything was hit --- */ unitHit = AnyoneBetween ((int) xPos, (int) unit->y, (int) xPosEnd, (int) unit->y); if (unitHit) { /* --- Something was hit --- */ /* --- Laser shot only goes this far --- */ xPosEnd = UnitScreenX (unitHit); /* --- Destroy the unit --- */ unitHit->bDestroy = TRUE; unit->bDestroy = TRUE; /* --- Special effects of destruction --- */ AddExplosion (unitHit); } /* --- Draw the laser --- */ gdk_draw_line (pixmap, penWhite, xPos, unit->y, xPosEnd, unit->y); /* --- Get real coordinates of laser --- */ unit->x = GameX (xPosEnd); /* --- If laser has gone too far... --- */ if (DistanceBetween (unit, hero) > nScreenWidth / 2) { /* --- destroy it --- */ unit->bDestroy = TRUE; } } } }
void DrownCount(Object* self) { switch(self->routine) { case Routine_Init: self->routine = Routine_BubbleExpanding; self->map = Map_Bub; self->gfx = GFX_Bubble; Obj_SetVisible(self); Obj_SetBehind(self); self->actWid = 16; self->priority = 1; if(BTST(self->subtype, Subtype_Master)) { self->routine = Routine_Master; self->map = Map_Drown; self->gfx = GFX_Master; VAR_B(self, alwaysOneB) = self->subtype & ~Subtype_Master; goto _masterRoutine; } // Bubble self->anim = self->subtype; VAR_W(self, origXW) = self->x; self->velY = -Bubble_Velocity; // fall through case Routine_BubbleExpanding: AnimateSprite(self, Ani_Drown); // fall through case Routine_BubbleRising: // Still underwater? if(self->y >= vWaterpos1) { // Move bubbles with tunnel current if(fWtunnelmode) VAR_W(self, origXW) += 4; // Wobble self->x = VAR_W(self, origXW) + Bubble_Wobble[self->angle & 0x7F]; self->angle++; // Update appearance CheckNumberBubbleConversion(self); SpeedToPos(self); if(Object_IsVisible(self)) DisplaySprite(self); else DeleteObject(self); break; } else { // Reached surface? For small bubbles, this sets their anim to blank and will go routine 6 > 8 and die // Big bubbles actually glitch out when they reach the surface cause there aren't enough enim mappings! self->routine = Routine_BubbleDying; self->anim += 7; } // fall through case Routine_BubbleDying: case Routine_NumberUpdate: _display: // Update appearance CheckNumberBubbleConversion(self); AnimateSprite(self, Ani_Drown); DisplaySprite(self); break; case Routine_BubbleDead: case Routine_NumberDead: DeleteObject(self); break; // Once a number-bubble gets plastered to the screen, it enters this state which handles switching to the // "flashing number" animation. case Routine_NumberTransition: if(v_air > Drown_Air) { DeleteObject(self); break; } if(TimerZero(VAR_W(self, frameTimerW))) { self->routine = Routine_NumberUpdate; self->anim += 7; goto _display; } AnimateSprite(self, Ani_Drown); if(Object_IsVisible(self)) DisplaySprite(self); else DeleteObject(self); break; // The "master" object, spawned when Sonic goes underwater for the first time, goes into this routine forever. // It manages counting down the air meter, spawning bubbles/numbers, and drowning/killing Sonic. case Routine_Master: _masterRoutine: // If we're not currently drowning... if(VAR_W(self, drowningTimeW) == 0) { // Manage counting down the timer and stuff if(Player_IsDead() || !Player_IsUnderwater()) return; // Count down frames until the next second if(TimerNeg(VAR_W(self, frameTimerW), 59)) { VAR_W(self, bubbleFlagsW) = BubbleFlags_Enable; VAR_B(self, spawnTimerB) = RandomNumber(2); if(ShouldDing()) PlaySound_Special(SFX_Warning); // ding-ding else if(v_air <= Drown_Air) { if(v_air == Drown_Air) PlaySound(BGM_Drowning); // uh oh if(TimerNeg(VAR_B(self, sillyTimerB), VAR_B(self, alwaysOneB))) BSET(VAR_W(self, bubbleFlagsW), BubbleFlags_SpawnNumber); } if(TimerNeg(v_air)) { // Drowning time. ResumeMusic(); f_lockmulti = 0x81; PlaySound_Special(SFX_Drown); VAR_B(self, spawnTimerB) = 10; VAR_W(self, bubbleFlagsW) = BubbleFlags_Enable; VAR_W(self, drowningTimeW) = Drown_Length; Player_ResetOnFloor(v_player); Player_SetAnimDrowning(); Player_SetInAir(); v_player->gfx |= 0x80; v_player->velY = 0; v_player->velX = 0; v_player->inertia = 0; f_nobgscroll = true; return; } goto _makeBubble; } } else { // Manage the drowning animation (Sonic falling offscreen) if(TimerZero(VAR_W(self, drowningTimeW))) { Player_SetDead(); return; } SpeedToPos(v_player); v_player->velY += Drown_Velocity; } // Bubble spawning enabled? if(VAR_W(self, bubbleFlagsW)) { if(TimerNeg(VAR_W(self, bubbleTimerW))) { _makeBubble: VAR_W(self, bubbleTimerW) = RandomNumber(16); if(auto bubble = FindFreeObj()) { auto bubble = &v_objspace[slot]; bubble->id = ID_DrownCount; bubble->x v_player->x + (Player_IsFlipped() ? -Bubble_OffsX : Bubble_OffsX); bubble->y = v_player->y; bubble->angle = Player_IsFlipped() ? Bubble_AngleFlipped : 0; bubble->subtype = Subtype_SmallBubble; // If we're doing drowning-bubbles.. if(VAR_W(self, drowningTimeW) != 0) { VAR_W(self, bubbleTimerW) &= 7; bubble->y = v_player->y - Bubble_DrownOffsY; bubble->angle = RandomNumber(256); // 1/4 bubbles are made bigger if((v_framecount & 3) == 0) bubble->subtype = Subtype_MediumBubble; } else if(ShouldSpawnNumberBubble(self)) { BSET(VAR_W(self, bubbleFlagsW), BubbleFlags_NumberSpawned); bubble->subtype = GetCountdownDigit(); VAR_W(bubble, frameTimerW) = NumberBubble_Timer1; } if(TimerNeg(VAR_B(self, spawnTimerB))) VAR_W(self, bubbleFlagsW) = 0; } } } break; } }