// Filename : HANDLERS.C // Coded by : Scott Evans // Created/Modified : 21/3/98 // Description : Game object handling routines #include "handlers.h" // Variables from other modules extern PROGRAM_DATA pd; extern GAME_DATA gd; extern PERFORMANCE pbat,pbloke; extern BRIGHTNESS default_brightness,brightness[]; extern OBJECT_LIST_HEADER objects_list,wind_objects_list,info_objects,paused_objects,gun_objects,platform_objects,fan_objects; extern OBJECT *start_block,*bloke,*bat,*bonus_object; extern BACKGRND bg; extern BLOKE_DATA bd; extern SPRITE_DATA_INFO font_sprite_info; extern u_byte bloke_dying_animation[]; extern COUNTER *score_counter,*block_counter,*max_block_counter,*bonus_counter; extern LEVEL_TIMER level_timer; extern SOUND_DATA *sounds; extern VOLUME game_volume; // Variables in this module u_long bouncy_factor[]={0.55*FPN24_8,1.15*FPN24_8,0.4*FPN24_8,1.3*FPN24_8,0.2*FPN24_8,0.2*FPN24_8,1.8*FPN24_8}; RECT bat_bounding_box[2]; word bonus_array[]={EXTRA_LIFE_BONUS,EXTRA_BOMB_BONUS,LEVEL_WARP_BONUS,EXTRA_TIME_BONUS,X10_BONUS,X2_BONUS,X2_BONUS,X2_BONUS,X5_BONUS,X5_BONUS}; // Used to draw bounding boxes #ifdef DEBUG GsBOX bboxes[3]={{TRANSPARENCY_ON,0,0,0,0,0xff,0xff,0xff}, {TRANSPARENCY_ON,0,0,0,0,0xff,0x0,0x0}, {TRANSPARENCY_ON,0,0,0,0,0x0,0x0,0xff}}; #endif // Function : HandleBat() // Coded by : Scott Evans // Created/Modified : 21/3/98 // Description : Controls the bat // Parameters : o - pointer to the bat object // Returns : None // Notes : None void HandleBatObject(OBJECT *o) { static long speedup; word row,column,b1,b2,bs,bx,x; // Move the bat left if(!bloke->dying || gd.bonus_level) { if(gd.demo_mode) { if(o->type.s.current_frame==BAT_RIGHT) x=o->screen.vx+10; else x=o->screen.vx+o->w-10; bx=bloke->screen.vx+(bloke->w>>1); // Calculate the bats velocity bs=bx-x; if(bs<-3)bs=-3; if(bs>3)bs=3; if(start_block->dying) o->velocity.vx=bs<velocity.vx=0; } // Reverse the controls of the bat if(bd.reverse) { ReverseControlEffect(o); if(bd.reverse_timer) bd.reverse_timer--; else bd.reverse=0; // Switch the controls around if(pd.pad&PADleft) { pd.pad&=~PADleft; pd.pad|=PADright; } else if(pd.pad&PADright) { pd.pad&=~PADright; pd.pad|=PADleft; } } if((pd.pad&PADleft && !gd.demo_mode) || (gd.demo_mode && bs<0)) { // Test for edge of screen if(o->screen.vxscreen.vx=GAME_SCREEN_X; o->position.vx=o->screen.vx<velocity.vx=0; } // Have we hit the start block if(!start_block->dying && o->screen.vxscreen.vx+start_block->w && o->screen.vx>start_block->screen.vx) { if(gd.bonus_type!=BT_CATCH) { o->screen.vx=start_block->screen.vx+start_block->w; o->position.vx=o->screen.vx<velocity.vx=0; } } if(!gd.demo_mode && o->screen.vx>GAME_SCREEN_X && (o->screen.vx>start_block->screen.vx+start_block->w || o->screen.vxscreen.vx || start_block->dying)) o->velocity.vx=-((pbat.vel.vx*speedup)>>FP24_8); // Check there are no blocks in the way column=o->screen.vx>>4; b1=GetMapBlock(&bg,MAX_MAP_SCREEN_ROWS-1,column); b2=GetMapBlock(&bg,MAX_MAP_SCREEN_ROWS-2,column); if(b1screen.vx=(column<<4)+bg.bw-1; o->position.vx=o->screen.vx<velocity.vx=0; } } // Move the bat right if((pd.pad&PADright && !gd.demo_mode) || (gd.demo_mode && bs>0)) { // Test for edge of screen if(o->screen.vx>GAME_SCREEN_W-o->w) { o->screen.vx=GAME_SCREEN_W-o->w; o->position.vx=o->screen.vx<velocity.vx=0; } // Have we hit the start block if(!start_block->dying && o->screen.vx+o->w>start_block->screen.vx && o->screen.vx+o->wscreen.vx+start_block->w) { if(gd.bonus_type!=BT_CATCH) { o->screen.vx=start_block->screen.vx-o->w; o->position.vx=o->screen.vx<velocity.vx=0; } } if(!gd.demo_mode && o->screen.vxw && (o->screen.vx+o->wscreen.vx || o->screen.vx+o->w>start_block->screen.vx+start_block->w || start_block->dying)) o->velocity.vx=((pbat.vel.vx*speedup)>>FP24_8); // Check there are no blocks in the way column=(o->screen.vx+o->w)>>4; b1=GetMapBlock(&bg,MAX_MAP_SCREEN_ROWS-1,column); b2=GetMapBlock(&bg,MAX_MAP_SCREEN_ROWS-2,column); if(b1screen.vx=(column<<4)-o->w; o->position.vx=o->screen.vx<velocity.vx=0; } } // Switch bat around if((pd.pad&PADcross && !(pd.buttons_down&PADcross) && !gd.demo_mode && !gd.leaving) || ((gd.demo_mode && start_block->dying && !(rand()%BAT_SWITCH_RATE)))) { if(o->type.s.current_frame==BAT_LEFT) { o->type.s.current_frame=BAT_RIGHT; } else { o->type.s.current_frame=BAT_LEFT; } SetSpriteTexture(&o->type.s,o->type.s.current_frame); } // If square is held down speed up the bat if(!gd.demo_mode) { if(pd.buttons_down&(PADL2|PADR2|PADL1|PADR1)) speedup=2<0) { { row=o->screen.vy>>4; column=o->screen.vx>>4; CreateExplosionSprite(row,column-1,1); CreateExplosionSprite(row,column+5,0); CreateExplosionSprite(row-1,column+2,0); if(!(gd.cheats_on&CC_INFINITE_BOMBS)) { gd.no_bombs--; KillIconSprite(&info_objects,gd.bomb_icons[gd.no_bombs]); } } } if(!(pd.pad&(PADright|PADleft))) o->velocity.vx=0; } } } // Function : ReverseControlEffect() // Coded by : Scott Evans // Created/Modified : 15/3/98 // Description : Shows that the bat is effected by reverse controls // Parameters : b - pointer to bat object // Returns : None // Notes : None void ReverseControlEffect(OBJECT *b) { OBJECT *o=CreateObject(&objects_list,PARTICLE_OBJECT); word x,y; // Create a particle if(o) { SetObjectsDefaultProperties(o); SetObjectsHandler(o,HandleBonusTrail); SetObjectsTimer(o,15); o->type.p.type_code=PTILE; o->type.p.type.ptile.w=1; o->type.p.type.ptile.h=1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; if(gd.demo_mode) SetObjectsBrightness(o,&brightness[GAME_DEMO_BRIGHTNESS]); else SetObjectsBrightness(o,&brightness[GAME_REVERSE_BRIGHTNESS]); SetObjectsOtOffset(o,1); x=rand()%48; y=rand()%16; SetObjectsPosition(o,b->screen.vx+x,b->screen.vy+y,0); o->parent=b; } } // Function : HandleExplosionObject() // Coded by : Scott Evans // Created/Modified : 21/3/98 // Description : Controls the explosion objects // Parameters : o - pointer to the explosion object // Returns : None // Notes : None void HandleExplosionObject(OBJECT *o) { // If the explosion is alive fade it down if(o->timer && o->is_fading) { o->timer--; FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],15<type.s.current_frame==o->type.s.max_frames-1) { o->type.s.animation_on=0; RemoveObjectFromList(&objects_list,o); gd.shake_screen=0; } } else { RemoveObjectFromList(&objects_list,o); gd.shake_screen=0; } } // Function : HandleExplosionFragment() // Coded by : Scott Evans // Created/Modified : 21/3/98 // Description : Controls the explosion fragment objects // Parameters : o - pointer to the explosion fragment // Returns : None // Notes : None void HandleExplosionFragment(OBJECT *o) { u_byte is_fading=FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],40<blink && !(o->type.p.timer%4)) o->blink_rate=1<<((rand()%3)+1); // Is it still active if(o->type.p.timer>0) o->type.p.timer--; // Kill fragment if(!o->type.p.timer || !is_fading || o->screen.vxscreen.vx>GAME_SCREEN_W || o->screen.vy>GAME_SCREEN_H || o->screen.vydying) { if(o->timer && !gd.lspr_clear) o->timer--; // Release the bloke when triangle is pressed or the timer runs out if((pd.pad&PADtriangle && !gd.demo_mode) || !o->timer) { if(!gd.lspr_clear) { o->type.s.animation_on=1; // Start the bloke bouncing bloke->can_move=1; bloke->type.s.animation_on=1; bloke->wind_effect=1; // Move bloke towards bat if(o->screen.vx+o->w<=bat->screen.vx) { SetObjectsVelocity(bloke,0,-2,0); bloke->velocity.vx=pbloke.vel.vx; } else { SetObjectsVelocity(bloke,0,-2,0); bloke->velocity.vx=-pbloke.vel.vx; } SetObjectsAcceleration(bloke,0,0,0); bloke->acceleration.vy=pbloke.acc.vy; // Start the level timer StartLevelTimer(); gd.game_started=1; } } // Is it time to remove the start block if(o->type.s.current_frame==o->type.s.max_frames-1) { o->type.s.animation_on=0; o->type.s.s.attribute=TRANSPARENCY_ON|BG_PLUS_SP; o->dying=1; StartObjectFading(o); } } else { // Time to remove the start block if(o->is_fading) FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],20<visible=0; o->active=0; o->allow_fading=0; } } } // Function : HandleBlokeObject() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Controls the bloke // Parameters : o - pointer to the bloke // Returns : None // Notes : None void HandleBlokeObject(OBJECT *o) { OBJECT *p; word row,column,c,hit,block; if(!o->dying) { // Check for collisions with any moving platforms p=platform_objects.start; while(p) { Bloke2Platform(o,p); p=p->next; } // Is this the real bloke if(!o->parent) { if(!gd.demo_mode && !gd.bonus_level && !bd.invisible && !bd.teleporting && start_block->dying) { if(!(pd.pad&PADsquare)) { bd.beam_timer=0; //if(bd.beam) // RemoveObjectFromList(&objects_list,bd.beam); bd.beam=0; } if(pd.pad&PADsquare) { bd.beam_timer++; //if(!bd.beam) // bd.beam=CreateBeamObject(); if(bd.beam_timer<25) { MoveBlokeEffect(o); if(o->screen.vx+(o->w>>1)>bat->screen.vx+(bat->w>>1)) o->velocity.vx-=0.08*FPN24_8; else o->velocity.vx+=0.08*FPN24_8; } } } // Super bloke bit if(bd.super) { // Show the super bloke effect if(!bd.teleporting) { SuperBlokeEffect(o); bd.super_timer--; if(!bd.super_timer) bd.super=0; } } // Invisible effect if(bd.invisible) { if(bd.invisible_timer>0) bd.invisible_timer--; else { bd.invisible=0; o->visible=1; o->blink=0; SetObjectsBrightness(o,&default_brightness); } } // Are we in the middle of teleporting if(bd.teleporting) { // Wait for all the teleport particles to gather if(bd.teleport_finished<=0) { bd.teleporting=0; o->can_move=1; o->visible=1; SetObjectsPosition(o,bd.tx-(bg.bw>>1),bd.ty-(bg.bh>>1),0); } } if(bd.shield) { if(bd.shield_timer) { if(!bd.teleporting) { ShieldEffect(o); // Shield protects him from the wind o->wind_effect=0; bd.shield_timer--; } } else { bd.shield=0; // Allow winds to effect him o->wind_effect=1; } } } // Slow the bloke down if not in any wind if(!o->in_wind) { word xv; if(o->velocity.vx>pbloke.vel.vx) { // Reduce velocity xv=(o->velocity.vx-pbloke.vel.vx)/10; o->velocity.vx-=xv; } else if(o->velocity.vx<-pbloke.vel.vx) { // Increase velocity xv=(abs(o->velocity.vx)-pbloke.vel.vx)/10; o->velocity.vx+=xv; } } // Test for collisions with the bat o->box.x=o->screen.vx+3; o->box.y=o->screen.vy+o->h-3; UpdateBoundingBoxes(); // Check for collisions with bat if(o->velocity.vy>0) { if(BoundingBoxTest(&o->box,&bat_bounding_box[BAT_PLATFORM])) { // Must have hit the free platform if(bat->type.s.current_frame==BAT_LEFT) { bat->type.s.current_frame=BAT_RIGHT; SetObjectsPosition(o,bat->screen.vx+2,bat->screen.vy-4,0); o->velocity.vx=pbloke.vel.vx; } else { bat->type.s.current_frame=BAT_LEFT; SetObjectsPosition(o,bat->screen.vx+40,bat->screen.vy-4,0); o->velocity.vx=-pbloke.vel.vx; } o->velocity.vy=-((o->velocity.vy*bouncy_factor[BAT])>>FP24_8); if(abs(o->velocity.vy)velocity.vy=-pbloke.min_vel.vy; SetSpriteTexture(&bat->type.s,bat->type.s.current_frame); o->direction=0; if(gd.bonus_type==BT_CATCH) { OBJECT *bonus; // Create a bonus bonus=CreateBonusSprite(o->screen.vx,o->screen.vy,BONUS_POINTS_START); bonus->extra[0]=1; AddToCounter(bonus_counter,1); o->dying=1; o->extra[0]=1; //o->type.s.s.attribute=TRANSPARENCY_ON; o->velocity.vy=-3*FPN24_8; } PlaySoundEffect(sounds,&game_volume,SFX_HIT_BAT); } else { // Test for other bits of bat if(BoundingBoxTest(&o->box,&bat_bounding_box[BAT_NONSAFE])) { // Kill the bloke KillBloke(o); } } } hit=0; if(o->can_move) { if(o->velocity.vy<=0) { if(o->screen.vyscreen.vy=GAME_SCREEN_Y; o->position.vy=o->screen.vy<velocity.vy=-(o->velocity.vy*bouncy_factor[CEILING])>>FP24_8; } // Bloke is moving up the screen, test hitting bottom of blocks row=o->screen.vy>>4; c=o->screen.vx+(o->w>>1); column=c>>4; if(row>=0) { // Test middle of bloke if((block=GetMapBlock(&bg,row,column))>4; if((block=GetMapBlock(&bg,row,column))>4; if((block=GetMapBlock(&bg,row,column))screen.vy>GAME_SCREEN_H-o->h) { o->screen.vy=GAME_SCREEN_H-o->h; o->position.vy=o->screen.vy<velocity.vy=-((o->velocity.vy*bouncy_factor[FLOOR])>>FP24_8); if(bd.shield && o->velocity.vy>-2<velocity.vy=-2<direction++; if(!bd.shield) { if(!o->parent) ResetBlockCount(1); // Just about to die if(o->direction==2) PlaySoundEffect(sounds,&game_volume,SFX_OHOH); } PlaySoundEffect(sounds,&game_volume,SFX_HIT_FLOOR); } // How many times has he hit the floor if(o->direction>3 && !bd.shield) { KillBloke(o); } // Bloke is moving down the screen row=(o->screen.vy+o->h-1)>>4; column=(o->screen.vx+(o->w>>1))>>4; if(row>=0 && rowscreen.vy=(row<<4)-o->h; o->velocity.vy=-(1.5*FPN24_8);//(o->velocity.vy*bouncy_factor[BLOCK])>>FP24_8; } } } if(hit) { //o->velocity.vy=-(o->velocity.vy*bouncy_factor[BLOCK])>>FP24_8; if(!bd.super) { if(hit==BOTTOM) { o->screen.vy=(row<<4)+16; if(block>=FIRST_DESTRUCTIBLE_MAP_BLOCK && block<=LAST_DESTRUCTIBLE_MAP_BLOCK) o->velocity.vy=-(o->velocity.vy*bouncy_factor[BLOCK])>>FP24_8;//1.5*FPN24_8; else o->velocity.vy=-(o->velocity.vy*bouncy_factor[SOLID_BLOCK])>>FP24_8; } o->position.vy=o->screen.vy<velocity.vx<0) { // Check left side of screen if(o->screen.vxscreen.vx=GAME_SCREEN_X; o->position.vx=GAME_SCREEN_X<velocity.vx=pbloke.vel.vx; } // Bloke is moving left, test right side of blocks row=(o->screen.vy+(o->h>>1))>>4; column=(o->screen.vx+3)>>4; if(column>=0 && row>=0 && (block=GetMapBlock(&bg,row,column))velocity.vx=pbloke.vel.vx; o->screen.vx=(column<<4)+14; o->position.vx=o->screen.vx<screen.vx>(GAME_SCREEN_W-o->w)) { o->screen.vx=(GAME_SCREEN_W-o->w); o->position.vx=(GAME_SCREEN_W-o->w)<velocity.vx=-pbloke.vel.vx; } // Bloke is moving right, test left side of blocks row=(o->screen.vy+(o->h>>1))>>4; column=(o->screen.vx+o->w-3)>>4; if(column=0 && (block=GetMapBlock(&bg,row,column))velocity.vx=-pbloke.vel.vx; o->screen.vx=(column<<4)-o->w+4; o->position.vx=o->screen.vx<extra[0]) { if(!FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],30<extra[0]=0; RemoveObjectFromList(&objects_list,o); } } else { // When bloke has finished dying, off we go again if(o->type.s.current_frame==o->type.s.max_frames-1) { RemoveObjectFromList(&objects_list,o); if(!gd.no_lives && !gd.demo_mode) { // No lives left, game over gd.game_over=1; gd.timer=5*SECOND; } else { // Have we killed the real bloke if(!o->parent && gd.bonus_type!=BT_CATCH) { // If we have restart him on the block bloke=CreateBlokeSprite(); PositionStartBlock(start_block); SetObjectsBrightness(start_block,&default_brightness); SetObjectsPosition(bloke,start_block->screen.vx,start_block->screen.vy+5-bloke->h,0); bat->can_move=1; } } } } } } // Function : KillBloke() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Kill off the bloke object // Parameters : o - pointer to the bloke // Returns : None // Notes : None void KillBloke(OBJECT *o) { // Is this the real bloke if(!o->parent) { // Stop any effects bd.super=0; bd.invisible=0; bd.reverse=0; bd.shield=0; // Used to count number of times bloke hits the ground o->direction=0; if(gd.no_lives && !gd.leaving && !gd.bonus_level && !gd.demo_mode && !(gd.cheats_on&CC_INFINITE_LIVES)) { gd.no_lives--; KillIconSprite(&info_objects,gd.life_icons[gd.no_lives]); } if(!gd.bonus_level) { if(!o->parent) ResetBlockCount(1); bat->velocity.vx=0; } } o->dying=1; o->can_move=0; o->type.s.current_frame=0; o->type.s.animation_on=1; o->type.s.max_frames=6; o->type.s.frame_rate=5; o->type.s.frames_list=&bloke_dying_animation[0]; PlaySoundEffect(sounds,&game_volume,SFX_BLOKE_DEAD); } // Function : SetBoundingBoxes() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Sets the sizes of bounding boxes // Parameters : None // Returns : None // Notes : None void SetBoundingBoxes(void) { // Set width and height of collision areas bat_bounding_box[BAT_PLATFORM].w=BAT_PLATFORM_BOUNDING_BOX_WIDTH; bat_bounding_box[BAT_PLATFORM].h=BAT_PLATFORM_BOUNDING_BOX_HEIGHT; bat_bounding_box[BAT_NONSAFE].w=BAT_NONSAFE_BOUNDING_BOX_WIDTH; bat_bounding_box[BAT_NONSAFE].h=BAT_NONSAFE_BOUNDING_BOX_HEIGHT; // Set y screen coordinate bat_bounding_box[BAT_PLATFORM].y=bat->screen.vy+6; bat_bounding_box[BAT_NONSAFE].y=bat->screen.vy+8; UpdateBoundingBoxes(); } // Function : UpdateBoundingBoxes() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Updates positions of bounding boxes // Parameters : None // Returns : None // Notes : None void UpdateBoundingBoxes(void) { if(bat->type.s.current_frame==BAT_RIGHT) { bat_bounding_box[BAT_PLATFORM].x=bat->screen.vx; bat_bounding_box[BAT_NONSAFE].x=bat->screen.vx+bat->w-BAT_PLATFORM_BOUNDING_BOX_WIDTH-10; } else { bat_bounding_box[BAT_PLATFORM].x=bat->screen.vx+bat->w-BAT_PLATFORM_BOUNDING_BOX_WIDTH-2; bat_bounding_box[BAT_NONSAFE].x=bat->screen.vx; } } #ifdef DEBUG // Function : SortBoundingBoxes() // Coded by : Scott Evans // Created/Modified : 8/3/98 // Description : Adds bounding boxes to ordering table // Parameters : ot - ordering table // priority - ordering table priority // Returns : None // Notes : Only used for debugging purposes void SortBoundingBoxes(GsOT *ot,u_word priority) { u_byte i; bboxes[0].x=bat_bounding_box[BAT_PLATFORM].x; bboxes[0].y=bat_bounding_box[BAT_PLATFORM].y; bboxes[0].w=bat_bounding_box[BAT_PLATFORM].w; bboxes[0].h=bat_bounding_box[BAT_PLATFORM].h; bboxes[1].x=bat_bounding_box[BAT_NONSAFE].x; bboxes[1].y=bat_bounding_box[BAT_NONSAFE].y; bboxes[1].w=bat_bounding_box[BAT_NONSAFE].w; bboxes[1].h=bat_bounding_box[BAT_NONSAFE].h; bboxes[2].x=bloke->box.x; bboxes[2].y=bloke->box.y; bboxes[2].w=bloke->box.w; bboxes[2].h=bloke->box.h; for(i=0;i<3;i++) GsSortBox(&bboxes[i],ot,priority); } #endif // Function : DestroyMapBlock() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Bloke has hit a block // Parameters : o - object pointer // r,c - position in map // b - ID of hit block // Returns : None // Notes : None void DestroyMapBlock(OBJECT *o,word r,word c,word b) { if((b>=FIRST_DESTRUCTIBLE_MAP_BLOCK && b<=LAST_DESTRUCTIBLE_MAP_BLOCK) || bd.super) { PARTICLE_EXPLOSION e; // Give a point AddToCounter(score_counter,1); // Create a few fragments SetParticleExplosion(&e,&objects_list,HandleExplosionFragment,6,280,1,1,0,0); setVECTOR(&e.maxvel,1,2,0); setVECTOR(&e.acc,0,0.1*FPN24_8,0); if(gd.demo_mode) { e.b.r=default_brightness.r; e.b.g=default_brightness.g; e.b.b=default_brightness.b; } else { e.b.r=brightness[GAME_MAX_BRIGHTNESS].r; e.b.g=brightness[GAME_MAX_BRIGHTNESS].g; e.b.b=brightness[GAME_MAX_BRIGHTNESS].b; } setRECT(&e.r,c<<4,r<<4,bg.bw,bg.bh); CreateParticleExplosion(&e); SetMapBlock(&bg,r,c,FIRST_BACKGROUND_MAP_BLOCK); // Make the block spin off screen CreateBlockSprite(r,c,b); // Shall we give a bonus if(b=FIRST_INDUSTRUCTIBLE_BLOCK && b<=LAST_INDUSTRUCTIBLE_BLOCK && gd.bonus_type==BT_NONE) PlaySoundEffect(sounds,&game_volume,SFX_HIT_INDUSTRUCTIBLE_BLOCK); else { // Which Type of block was hit switch(b) { case EXPLOSION_MAP_BLOCK: SelectBlockEffect(BE_EXPLODE,r,c); break; case EXTRA_LIFE_MAP_BLOCK: CreateExtraLife(); break; case EXTRA_BOMB_MAP_BLOCK: CreateExtraBomb(); break; case EXTRA_TIME_MAP_BLOCK: AddToTime(15); break; case EXPANDING_MAP_BLOCK: SelectBlockEffect(BE_EXPAND,r,c); break; case UP_ARROW_MAP_BLOCK: ScrollLevel(); PlaySoundEffect(sounds,&game_volume,SFX_UP_ARROW); break; case SUPER_BLOKE_MAP_BLOCK: SelectBlockEffect(BE_SUPER,0,0); break; case SPLIT_BLOKE_MAP_BLOCK: SelectBlockEffect(BE_SPLIT,0,0); break; case INVISIBLE_BLOKE_MAP_BLOCK: SelectBlockEffect(BE_INVISIBLE,0,0); break; case TELEPORT_MAP_BLOCK: SelectBlockEffect(BE_TELEPORT,0,0); break; case REVERSE_CONTROLS_MAP_BLOCK: SelectBlockEffect(BE_REVERSE,0,0); break; case _4_HIT_MAP_BLOCK: SetMapBlock(&bg,r,c,_3_HIT_MAP_BLOCK); PlaySoundEffect(sounds,&game_volume,SFX_HIT_BLOCK4); break; case _3_HIT_MAP_BLOCK: SetMapBlock(&bg,r,c,_2_HIT_MAP_BLOCK); PlaySoundEffect(sounds,&game_volume,SFX_HIT_BLOCK3); break; case _2_HIT_MAP_BLOCK: SetMapBlock(&bg,r,c,_1_HIT_MAP_BLOCK); PlaySoundEffect(sounds,&game_volume,SFX_HIT_BLOCK2); break; case EXPLODE_GUNS_MAP_BLOCK: KillActiveGuns(); break; case EXPLODE_PLATFORMS_MAP_BLOCK: KillActivePlatforms(); break; case RANDOM_EFFECT_MAP_BLOCK: SelectBlockEffect(rand()%BE_NUMBER_EFFECTS,r,c); break; case SHIELD_MAP_BLOCK: SelectBlockEffect(BE_SHIELD,0,0); break; default: PlaySoundEffect(sounds,&game_volume,SFX_HIT_BLOCK); break; } } } else if(gd.bonus_type==BT_NONE) PlaySoundEffect(sounds,&game_volume,SFX_HIT_INDUSTRUCTIBLE_BLOCK); } // Function : SelectBlockEffect() // Coded by : Scott Evans // Created/Modified : 12/8/98 // Description : Selects an effect // Parameters : effect - type of effect // r,c - map position // Returns : None // Notes : None void SelectBlockEffect(u_byte effect,word r,word c) { switch(effect) { case BE_EXPLODE: CreateExplosionSprite(r,c,1); break; case BE_EXPAND: CreateExpandingBlock(r,c); break; case BE_SUPER: bd.super=1; bd.super_timer=SECOND*6; PlaySoundEffect(sounds,&game_volume,SFX_SUPER_BLOKE); break; case BE_SPLIT: CreateDecoyBloke(3); break; case BE_INVISIBLE: if(!bd.invisible) { bd.invisible=1; bd.invisible_timer=SECOND*4; SetObjectsBrightness(bloke,&brightness[GAME_INVISIBLE_BLOKE_BRIGHTNESS]); bloke->blink=1; bloke->blink_rate=4; bd.super=0; PlaySoundEffect(sounds,&game_volume,SFX_INVISIBLE); } break; case BE_TELEPORT: TeleportBloke(); break; case BE_REVERSE: bd.reverse=1; bd.reverse_timer=SECOND*3; PlaySoundEffect(sounds,&game_volume,SFX_REVERSE_CONTROLS); break; case BE_SHIELD: bd.shield=1; bd.shield_timer=SECOND*6; PlaySoundEffect(sounds,&game_volume,SFX_SHIELD); break; } } // Function : HandleBlockObject() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Handles a spinning block // Parameters : o - pointer to the bloke // Returns : None // Notes : None void HandleBlockObject(OBJECT *o) { OBJECT *d; long rot; if(o->timer) { o->timer--; if(block_counter) d=block_counter->type.bar.bar; else d=0; if(o->type.s.current_frame!=HIT_DIAMOND_SPRITE) { if(!gd.bonus_level && !gd.demo_mode && d && o->extra[1] && o->type.s.current_framevelocity.vx=(d->position.vx-o->position.vx)/25; o->velocity.vy=(d->position.vy-o->position.vy)/25; } rot=(ONE*(o->velocity.vx>>FP24_8))<<2; if(abs(rot)type.s.s.rotate+=rot; if(gd.cheats_on&CC_LARGE_BLOCKS) { if(o->type.s.s.scalextype.s.s.scalex+=400; o->type.s.s.scaley+=400; } } if(!o->extra[0] && o->screen.vx>BLOCK_POS_X-25 && o->screen.vxscreen.vy>BLOCK_POS_Y-4 && o->screen.vyextra[0]=1; // Increase block count if(!gd.bonus_level) { if(block_counter && block_counter->counter>BLOCK_COUNTER_FULL) { // Save block type on stack gd.block_stack[gd.block_sp]=o->type.s.current_frame; gd.block_sp++; SubtractFromCounter(block_counter,1); PlaySoundEffect(sounds,&game_volume,SFX_FILL_BONUS_BAR); if(block_counter->countercounter) SubtractFromCounter(max_block_counter,1); } } } FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],35<timer) { RemoveObjectFromList(&objects_list,o); } } // Function : HandleBonusObject() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Handles a bonus // Parameters : o - pointer to the bloke // Returns : None // Notes : None void HandleBonusObject(OBJECT *o) { // If it is off screen kill it if(o->screen.vy>GAME_SCREEN_H || o->screen.vytmp=0; RemoveObjectFromList(&objects_list,o); } // Fade object as it moves down screen if(o->is_fading) if(o->velocity.vy>0) FadeObjectBrightness(o,&brightness[GAME_DEMO_BRIGHTNESS],35<extra[0] || (o->screen.vx+(o->w>>1)>bat->screen.vx+5 && o->screen.vx+(o->w>>1)screen.vx+bat->w+5 && o->screen.vy>bat->screen.vy)) { if(!o->extra[0]) { o->screen.vy=bat->screen.vy; o->position.vy=o->screen.vy<extra[0]=0; SetObjectsVelocity(o,0,-1,0); SetObjectsAcceleration(o,0,-0.1,0); o->timer--; o->tmp=1; if(!gd.demo_mode) { // Which bonus has been collected switch(o->direction) { case EXTRA_TIME_BONUS: if(gd.bonus_type) AddToTime(3); else AddToTime(15*gd.bonus_multiplier); break; case X2_BONUS: gd.bonus_multiplier=2; CreateScoreMultiplier(X2_BONUS); break; case X5_BONUS: gd.bonus_multiplier=5; CreateScoreMultiplier(X5_BONUS); break; case X10_BONUS: gd.bonus_multiplier=10; CreateScoreMultiplier(X10_BONUS); break; case EXTRA_LIFE_BONUS: CreateExtraLife(); break; case EXTRA_BOMB_BONUS: CreateExtraBomb(); break; // Skip this level case LEVEL_WARP_BONUS: gd.level_complete=1; gd.level_warp=1; CopyBrightness(&default_brightness,&brightness[GAME_DEMO_BRIGHTNESS]); StartObjectFading(bg.block); StopLevelTimer(); break; } if(o->direction>=BONUS_POINTS_START && o->direction<=BONUS_POINTS_END) AddToCounter(score_counter,((o->direction-BONUS_POINTS_START+1)*100)*gd.bonus_multiplier); // Don't need o->direction anymore can use it for something else o->direction=GAME_EFFECTS_BRIGHTNESS+(rand()%5); PlaySoundEffect(sounds,&game_volume,SFX_COLLECT_BONUS); } } //if(o->tmp) // BonusTrailEffect(o); if(gd.cheats_on&CC_LARGE_BONUSES && o->tmp) { if(o->type.s.s.scalextype.s.s.scalex+=400; o->type.s.s.scaley+=400; } } } // Function : HandleExpandingBlock() // Coded by : Scott Evans // Created/Modified : 22/3/98 // Description : Handles the expanding blocks // Parameters : o - pointer to an object // Returns : None // Notes : None void HandleExpandingBlock(OBJECT *o) { if(!o->timer || !o->is_fading) RemoveObjectFromList(&objects_list,o); else { FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],20<timer) o->timer--; } } // Function : ScrollLevel() // Coded by : Scott Evans // Created/Modified : 24/3/98 // Description : Scrolls the level up one row // Parameters : None // Returns : None // Notes : Also places another up arrow block if not at top of level void ScrollLevel(void) { MoveBackground(&bg,UP); PositionUpArrowMapBlock(); } // Function : SuperBlokeEffect() // Coded by : Scott Evans // Created/Modified : 25/3/98 // Description : Shows the golden trail // Parameters : b - pointer to bloke object // Returns : None // Notes : None void SuperBlokeEffect(OBJECT *b) { OBJECT *o=CreateObject(&objects_list,PARTICLE_OBJECT); word w; // Create a particle if(o) { SetObjectsDefaultProperties(o); SetObjectsHandler(o,HandleSuperBlokeTrail); SetObjectsTimer(o,25); w=(b->w>>1)-1; w+=(2-(rand()%5)); SetObjectsPosition(o,b->screen.vx+w,b->screen.vy+b->h-2,0); o->type.p.type_code=PTILE; o->type.p.type.ptile.w=(rand()%2)+1; o->type.p.type.ptile.h=(rand()%3)+1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; if(gd.demo_mode) SetObjectsBrightness(o,&brightness[GAME_DEMO_YELLOW_BRIGHTNESS]); else SetObjectsBrightness(o,&brightness[GAME_YELLOW_BRIGHTNESS]); } } // Function : HandleSuperBlokeTrail() // Coded by : Scott Evans // Created/Modified : 25/3/98 // Description : Handles the particles that make the golden trail // Parameters : o - pointer to object // Returns : None // Notes : None void HandleSuperBlokeTrail(OBJECT *o) { if(o->timer) { o->timer--; if(o->blink && !(o->timer%3)) o->blink_rate=1<<((rand()%3)+1); FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],10<>1)+((GAME_SCREEN_W>>1)-(rand()%(GAME_SCREEN_W-bloke->w))); y=(GAME_SCREEN_H>>1)+((GAME_SCREEN_H>>1)-(rand()%(GAME_SCREEN_H-bloke->h))); x=x>>4; y=y>>4; n++; } while(n<200 && !((b=GetMapBlock(&bg,y,x))>=FIRST_DESTRUCTIBLE_MAP_BLOCK && b<=LAST_DESTRUCTIBLE_MAP_BLOCK)); // Create a few particles for the effect for(n=0;ntype.p.type_code=PTILE; o->type.p.type.ptile.w=(rand()%3)+1; o->type.p.type.ptile.h=(rand()%2)+1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; SetObjectsBrightness(o,&brightness[GAME_MIN_BRIGHTNESS]); if(gd.demo_mode) { SetObjectsBrightness(o,&brightness[GAME_DEMO_BRIGHTNESS]); o->type.p.type.ptile.attribute=0; } } } x=(x<<4); y=(y<<4); bloke->can_move=0; bloke->visible=0; bloke->blink=0; bd.tx=x+(bg.bw>>1); bd.ty=y+(bg.bh>>1); bd.teleporting=1; bd.teleport_finished=n; // Cancel any other effects bd.invisible=0; SetObjectsBrightness(bloke,&default_brightness); PlaySoundEffect(sounds,&game_volume,SFX_TELEPORT); } // Function : HandleTeleportEffect() // Coded by : Scott Evans // Created/Modified : 30/3/98 // Description : Handles the teleport particles // Parameters : o - pointer to object // Returns : None // Notes : None void HandleTeleportEffect(OBJECT *o) { RECT r={bd.tx-1,bd.ty-1,2,2}; // Move all the particles towards the teleport point if(o->timer) { o->timer--; o->velocity.vx=((bd.tx<position.vx)/15; o->velocity.vy=((bd.ty<position.vy)/15; if(!gd.demo_mode) FadeObjectBrightness(o,&brightness[GAME_TELEPORT_BLOKE_BRIGHTNESS],30<screen.vx,o->screen.vy,&r)) { RemoveObjectFromList(&objects_list,o); bd.teleport_finished--; } } // Function : HandleSpringObject() // Coded by : Scott Evans // Created/Modified : 31/3/98 // Description : Handles the spring objects // Parameters : o - pointer to object // Returns : None // Notes : None void HandleSpringObject(OBJECT *o) { RECT r={bloke->screen.vx,bloke->screen.vy,bloke->w,bloke->h}; // Has the bloke hit a spring if(BoundingBoxTest(&r,&o->box)) { // Which direction to move bloke switch(o->direction) { case FACING_UP: if(bloke->velocity.vy>0) { o->type.s.animation_on=1; bloke->screen.vy=o->screen.vy-bloke->h; bloke->position.vy=bloke->screen.vy<velocity.vy=-(4*FPN24_8); } break; case FACING_DOWN: if(bloke->velocity.vy<0) { o->type.s.animation_on=1; bloke->screen.vy=o->screen.vy+o->h; bloke->position.vy=bloke->screen.vy<velocity.vy=(4*FPN24_8); } break; case FACING_LEFT: if(bloke->velocity.vx<0) { o->type.s.animation_on=1; bloke->velocity.vx=-(4*FPN24_8); } break; case FACING_RIGHT: if(bloke->velocity.vx>0) { o->type.s.animation_on=1; bloke->velocity.vx=(4*FPN24_8); } break; } } // if spring moves off screen destroy it if(o->screen.vy>GAME_SCREEN_H) { RemoveObjectFromList(&objects_list,o); //gd.no_springs--; } // Have we finished the animation if(o->type.s.current_frame==o->type.s.max_frames-1) { o->type.s.animation_on=0; o->type.s.current_frame=0; } } // Function : HandleGunObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles the gun objects // Parameters : o - pointer to object // Returns : None // Notes : None void HandleGunObject(OBJECT *o) { // Has gun moved off screen if(o->screen.vy>GAME_SCREEN_H) { o->dying=1; RemoveObjectFromList(&gun_objects,o); } // Is the bloke in range if(!bloke->dying && bloke->screen.vy+(bloke->h>>1)screen.vy+o->h && bloke->screen.vy+(bloke->h>>1)>o->screen.vy) { // Is a bullet from this gun still active if(!o->type.g.just_fired) { // Fire a bullet across the screen o->type.g.just_fired=1; o->type.g.s.animation_on=1; o->type.g.bullet=CreateObject(&objects_list,GsTILE1_OBJECT); if(o->type.g.bullet) { SetObjectsDefaultProperties(o->type.g.bullet); SetObjectsHandler(o->type.g.bullet,HandleBulletObject); if(gd.demo_mode) SetObjectsBrightness(o->type.g.bullet,&brightness[GAME_DEMO_YELLOW_BRIGHTNESS]); else SetObjectsBrightness(o->type.g.bullet,&brightness[GAME_YELLOW_BRIGHTNESS]); SetObjectsOtOffset(o,1); if(o->direction==FACING_LEFT) { SetObjectsPosition(o->type.g.bullet,o->screen.vx+o->w+2,o->screen.vy+(o->h>>1)-1,0); SetObjectsVelocity(o->type.g.bullet,3,0,0); } else { SetObjectsPosition(o->type.g.bullet,o->screen.vx-1,o->screen.vy+(o->h>>1)-1,0); SetObjectsVelocity(o->type.g.bullet,-3,0,0); } o->type.g.bullet->parent=o; } PlaySoundEffect(sounds,&game_volume,SFX_FIREGUN); } } if(o->type.g.s.animation_on) { if(o->type.g.s.current_frame==o->type.g.s.max_frames-1) { o->type.g.s.animation_on=0; o->type.g.s.current_frame=0; } } } // Function : HandleBulletObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles the bullets fired by the gun objects // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBulletObject(OBJECT *o) { RECT r={bloke->screen.vx,bloke->screen.vy,bloke->w,bloke->h}; word rw,cl,b; u_byte kill=0; // Is bullet off screen if(o->screen.vx>GAME_SCREEN_W || o->screen.vxscreen.vx,o->screen.vy,&r) && !bloke->dying) KillBloke(bloke),kill=1; } // Has the bullet hit a block rw=o->screen.vy>>4; cl=o->screen.vx>>4; if((b=GetMapBlock(&bg,rw,cl))=bg.area.x && clparent) o->parent->type.g.just_fired=0; RemoveObjectFromList(&objects_list,o); } } // Function : HandleTimerObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles the timer // Parameters : o - pointer to object // Returns : None // Notes : None void HandleTimerObject(OBJECT *o) { word n; if(o->timer) { o->timer--; // Decrement the timer every second if(!(o->timer%SECOND)) { o->direction--; n=MapCharacterToImage("0")+o->direction; o->type.gss.u=font_sprite_info.offsets[n].u; o->type.gss.v=font_sprite_info.offsets[n].v; } } else RemoveObjectFromList(&objects_list,o); } // Function : HandleMovingPlatformObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles the moving platform sprites // Parameters : o - pointer to object // Returns : None // Notes : None void HandleMovingPlatformObject(OBJECT *o) { word c; // Remove the object if it goes off screen if(o->screen.vy>GAME_SCREEN_H) RemoveObjectFromList(&platform_objects,o); // Decide which way to move the platform if(o->direction==FACING_LEFT) { c=(o->screen.vx+o->w)>>4; if(GetMapBlock(&bg,o->screen.vy>>4,c)direction=FACING_RIGHT; o->velocity.vx=-1*FPN24_8; o->screen.vx=(c<<4)-bg.bw; o->position.vx=o->screen.vx<screen.vx>>4; if(GetMapBlock(&bg,o->screen.vy>>4,c)direction=FACING_LEFT; o->velocity.vx=1*FPN24_8; o->screen.vx=(c<<4)+bg.bw; o->position.vx=o->screen.vx<screen.vy>GAME_SCREEN_H) { // Kill the wind associated with this fan RemoveObjectFromList(&wind_objects_list,o->type.f.w); // Kill the fan sprite RemoveObjectFromList(&fan_objects,o); } } // Function : HandlePausedObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles the game paused objects // Parameters : o - pointer to object // Returns : None // Notes : None void HandlePausedObject(OBJECT *o) { // Bounce the text if(!o->tmp && o->screen.vy>((GAME_SCREEN_H-o->h)>>1)+20) { o->velocity.vy=-5<screen.vy=((GAME_SCREEN_H-o->h)>>1)+20; o->position.vx=o->screen.vx<screen.vy>GAME_SCREEN_H+20) RemoveObjectFromList(&paused_objects,o); } // Function : HandleScoreMultiplierObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles the score multiplier icon // Parameters : o - pointer to object // Returns : None // Notes : None void HandleScoreMultiplierObject(OBJECT *o) { // Show the icon then fade it out if(o->timer) { o->timer--; FadeObjectBrightness(o,&brightness[GAME_MAX_BRIGHTNESS],30<is_fading) { RemoveObjectFromList(&objects_list,o); gd.multiplier_sprite=0; } } } // Function : HandleNewIconObject() // Coded by : Scott Evans // Created/Modified : 4/4/98 // Description : Handles a new icon // Parameters : o - pointer to object // Returns : None // Notes : None void HandleNewIconObject(OBJECT *o) { // Fade the new icon to full brightness FadeObjectBrightness(o,&brightness[GAME_MAX_BRIGHTNESS],30<is_fading) { SetObjectsHandler(o,HandleScoreInfoObjects); o->tmp=o->extra[0]; o->direction=FINISHED; SetObjectsHandler(o->parent,HandleScoreInfoObjects); o->parent->tmp=o->extra[1]; o->parent->direction=FINISHED; } } void HandleLevelCompleteObject(OBJECT *o) { static word y[]={80,130,160,210,300}; if(o->velocity.vy>0) { if(o->screen.vy>y[o->direction]) { o->screen.vy=y[o->direction]; o->position.vy=o->screen.vy<velocity.vy=-2<type.p.type_code=PTILE; o->type.p.type.ptile.w=(rand()%2)+1; o->type.p.type.ptile.h=(rand()%2)+1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; SetObjectsBrightness(o,&brightness[b->direction]); //x=8-(rand()&15); SetObjectsPosition(o,b->screen.vx-4,b->screen.vy,0); o->parent=b; } } // Function : HandleBonusTrail() // Coded by : Scott Evans // Created/Modified : 25/3/98 // Description : Handles the particles that make the golden trail // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBonusTrail(OBJECT *o) { if(o->timer) { o->timer--; FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],10<direction) { // Get ready to move all the objects case START_MOVING_ON_SCREEN: SetObjectsVelocity(o,0,2,0); o->direction=MOVING_ON_SCREEN; break; // Move all the objects onto the screen case MOVING_ON_SCREEN: if(o->screen.vy>pos[o->tmp]) { o->screen.vy=pos[o->tmp]; o->position.vy=o->screen.vy<direction=FINISHED; } break; // Get ready to move all the objects case START_MOVING_OFF_SCREEN: SetObjectsVelocity(o,0,-3,0); o->direction=MOVING_OFF_SCREEN; y=o->screen.vy-256; break; // Move all the objects off screen case MOVING_OFF_SCREEN: if(o->screen.vyscreen.vy=y; o->position.vy=y<direction=FINISHED; } break; case FINISHED: break; } } // Function : HandleBigTimerObject() // Coded by : Scott Evans // Created/Modified : 26/6/98 // Description : Handles the big timer // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBigTimerObject(OBJECT *o) { word n; if(o->timer) { o->timer--; // Decrement the timer every second if(!(o->timer%SECOND) && o->extra[0]>1 && level_timer.no_seconds<=5) { o->extra[0]--; n=BIG_NUMBER_0+o->extra[0]; o->type.gss.u=font_sprite_info.offsets[n].u; o->type.gss.v=font_sprite_info.offsets[n].v; o->type.gss.scalex=ONE*7; o->type.gss.scaley=ONE*7; o->visible=1; SetObjectsBrightness(o,&brightness[GAME_RED_BRIGHTNESS]); PlaySoundEffect(sounds,&game_volume,SFX_RUNNING_OUT_OF_TIME); } FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],12<timer<(5*SECOND)-3) { if(o->type.gss.scalex>600) { o->type.gss.scalex-=600; o->type.gss.scaley-=600; } else o->visible=0; } } else RemoveObjectFromList(&objects_list,o); } // Function : HandleIntroExplosionObject() // Coded by : Scott Evans // Created/Modified : 1/7/98 // Description : Controls the explosion objects // Parameters : o - pointer to the explosion object // Returns : None // Notes : None void HandleIntroExplosionObject(OBJECT *o) { extern OBJECT_LIST_HEADER intro_objects; // If the explosion is alive fade it down if(o->timer && o->is_fading) { o->timer--; FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],15<type.s.current_frame==o->type.s.max_frames-1) { o->type.s.animation_on=0; RemoveObjectFromList(&intro_objects,o); gd.shake_screen=0; } } else { RemoveObjectFromList(&intro_objects,o); gd.shake_screen=0; } } // Function : HandleBonusLevelObject() // Coded by : Scott Evans // Created/Modified : 1/7/98 // Description : Handles the bonus level message // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBonusLevelObject(OBJECT *o) { // Bounce the text if(o->timer) { o->timer--; o->extra[1]++; if(o->extra[0] && !(o->extra[1]%25) && o->timer>SECOND) { CreateBonusFirework(); CreateBonusFirework(); } } if(start_block->dying) { if(gd.bonus_type==BT_COLLECT) { o->timer=0; bonus_object->visible=1; bonus_object->extra[1]=1; bonus_object->allow_fading=1; } if(gd.bonus_type==BT_BLOCK) o->timer=0; } if(o->timer && o->screen.vy>((GAME_SCREEN_H-o->h)>>1)+20) { o->velocity.vy=-5<screen.vy=((GAME_SCREEN_H-o->h)>>1)+20; o->position.vx=o->screen.vx<screen.vy>GAME_SCREEN_H+20) { gd.bspr_clear=1; RemoveObjectFromList(&objects_list,o); } } // Function : HandleBonusCatcher() // Coded by : Scott Evans // Created/Modified : 3/7/98 // Description : Handles the bonus level catcher device // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBonusCatcher(OBJECT *o) { OBJECT *bonus; u_byte i; if(Object2Object(bloke,o)) { // Create a bonus bonus=CreateBonusSprite(bloke->screen.vx,bloke->screen.vy,BONUS_POINTS_START); bonus->extra[0]=1; // Give a bit of extra time for(i=0;i<5;i++) CreateBonusSprite(((rand()%GAME_SCREEN_W)>>4)<<4,0-(rand()%20),EXTRA_TIME_BONUS); // If we have got into the catcher restart him on the block bloke=CreateBlokeSprite(); PositionStartBlock(start_block); SetObjectsBrightness(start_block,&default_brightness); SetObjectsPosition(bloke,start_block->screen.vx,start_block->screen.vy+5-bloke->h,0); // Increase count AddToCounter(bonus_counter,1); // If this is the first one get rid of the arrow if(!bonus_counter->counter) bonus_object->extra[1]=2; } } // Function : HandleBonusArrow() // Coded by : Scott Evans // Created/Modified : 5/7/98 // Description : Handles the bonus level object // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBonusArrow(OBJECT *o) { // Fade it up or down switch(o->extra[1]) { case 1: FadeObjectBrightness(o,&brightness[GAME_GREEN_BRIGHTNESS],30<velocity.vy>0 && o->screen.vy>o->extra[0]) { o->screen.vy=o->extra[0]; o->position.vy=o->screen.vy<velocity.vy=-2*FPN24_8; } } // Function : HandleBonusDropper() // Coded by : Scott Evans // Created/Modified : 5/7/98 // Description : Handles the bloke droper // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBonusDropper(OBJECT *o) { if(o->timer) o->timer--; else { // Start the level timer StartLevelTimer(); o->extra[0]++; if(!(o->extra[0]%(1*SECOND)) && o->extra[1]>30) o->extra[1]-=10; } if(!(o->extra[0]%o->extra[1]) && !o->timer) { bloke=CreateBlokeSprite(); SetObjectsPosition(bloke,((rand()%GAME_SCREEN_W)>>4)<<4,-16,0); // Start the bloke bouncing bloke->can_move=1; bloke->type.s.animation_on=1; bloke->wind_effect=1; // Move bloke towards bat if(rand()&16) bloke->velocity.vx=pbloke.vel.vx; else bloke->velocity.vx=-pbloke.vel.vx; bloke->acceleration.vy=0.15*FPN24_8; } } // Function : HandleBonusFirework() // Coded by : Scott Evans // Created/Modified : 5/7/98 // Description : Handles the firework object // Parameters : o - pointer to object // Returns : None // Notes : None void HandleBonusFirework(OBJECT *o) { o->timer--; BonusFireworkTrail(o); if(o->velocity.vy>=0 || gd.kill_fireworks) { PARTICLE_EXPLOSION e; // Create a few fragments if(gd.paused) SetParticleExplosion(&e,&paused_objects,HandleExplosionFragment,10,280,1,1,1,4); else SetParticleExplosion(&e,&objects_list,HandleExplosionFragment,10,280,1,1,1,4); setVECTOR(&e.maxvel,2,2,0); setVECTOR(&e.acc,0,0.1*FPN24_8,0); setRECT(&e.r,o->screen.vx,o->screen.vy,4,4); e.b.r=o->brightness.r; e.b.g=o->brightness.g; e.b.b=o->brightness.b; CreateParticleExplosion(&e); if(gd.paused) RemoveObjectFromList(&paused_objects,o); else RemoveObjectFromList(&objects_list,o); } } // Function : BonusFireworkTrail() // Coded by : Scott Evans // Created/Modified : 5/7/98 // Description : Shows a trail for the firework // Parameters : f - pointer to firework object // Returns : None // Notes : None void BonusFireworkTrail(OBJECT *f) { OBJECT *o; if(gd.paused) o=CreateObject(&paused_objects,PARTICLE_OBJECT); else o=CreateObject(&objects_list,PARTICLE_OBJECT); // Create a particle if(o) { o->type.p.type_code=PTILE; o->type.p.type.ptile.w=(rand()%2)+1; o->type.p.type.ptile.h=(rand()%2)+1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; SetObjectsDefaultProperties(o); SetObjectsHandler(o,HandleFireworkTrail); SetObjectsTimer(o,10); SetObjectsBrightness(o,&brightness[f->tmp]); //x=8-(rand()&15); SetObjectsPosition(o,f->screen.vx,f->screen.vy,0); } } // Function : HandleFireworkTrail() // Coded by : Scott Evans // Created/Modified : 5/7/98 // Description : Handles the firework trail // Parameters : o - pointer to object // Returns : None // Notes : None void HandleFireworkTrail(OBJECT *o) { if(o->timer) { o->timer--; FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],5<timer) { o->timer--; FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],25<type.gss.scalextype.gss.scalex+=500; o->type.gss.scaley+=500; } else RemoveObjectFromList(&info_objects,o); } else RemoveObjectFromList(&info_objects,o); } // Function : ShieldEffect() // Coded by : Scott Evans // Created/Modified : 15/3/98 // Description : Shows that the bat is effected by reverse controls // Parameters : b - pointer to bat object // Returns : None // Notes : None void ShieldEffect(OBJECT *b) { OBJECT *o=CreateObject(&objects_list,PARTICLE_OBJECT); word x,y; // Create a particle if(o) { SetObjectsDefaultProperties(o); SetObjectsHandler(o,HandleBonusTrail); SetObjectsTimer(o,10); o->type.p.type_code=PTILE; o->type.p.type.ptile.w=1; o->type.p.type.ptile.h=1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; if(gd.demo_mode) SetObjectsBrightness(o,&brightness[GAME_DEMO_BRIGHTNESS]); else SetObjectsBrightness(o,&brightness[GAME_SHIELD_BRIGHTNESS]); SetObjectsOtOffset(o,1); x=rand()%10; y=rand()%10; SetObjectsPosition(o,b->screen.vx+4+x,b->screen.vy+y,0); o->parent=b; } } // Function : Bloke2Platform() // Coded by : Scott Evans // Created/Modified : 27/8/98 // Description : Checks collisions between moving platforms and blokes // Parameters : b - pointer to bloke object // p - pointer to moving platform // Returns : None // Notes : None void Bloke2Platform(OBJECT *b,OBJECT *p) { // Test for collisions with the bloke if(b->velocity.vy<0 && b->screen.vx+(b->w>>1)>=p->screen.vx && b->screen.vx+(b->w>>1)<=p->screen.vx+p->w && b->screen.vyscreen.vy+p->h && b->screen.vy>p->screen.vy) { // Bloke has hit bottom of moving platform b->screen.vy=p->screen.vy+p->h; b->position.vy=b->screen.vy<velocity.vy=-(b->velocity.vy*bouncy_factor[BLOCK])>>FP24_8; PlaySoundEffect(sounds,&game_volume,SFX_HIT_INDUSTRUCTIBLE_BLOCK); } else { if(b->velocity.vy>0 && b->screen.vx+(b->w>>1)>=p->screen.vx && b->screen.vx+(b->w>>1)<=p->screen.vx+p->w && b->screen.vy+b->h>p->screen.vy && b->screen.vy+b->hscreen.vy+p->h) { // Bloke has hit top of moving platform b->screen.vy=p->screen.vy-bloke->h; b->position.vy=b->screen.vy<velocity.vy=-1.5*FPN24_8; PlaySoundEffect(sounds,&game_volume,SFX_HIT_INDUSTRUCTIBLE_BLOCK); } else { if(b->velocity.vx<0 && b->screen.vy+(b->h>>1)>p->screen.vy && b->screen.vy+(b->h>>1)screen.vy+p->h && b->screen.vxscreen.vx+p->w && b->screen.vx>p->screen.vx) { // Bloke has hit right of moving platform b->screen.vx=p->screen.vx+p->w; b->position.vx=b->screen.vx<velocity.vx=-b->velocity.vx; PlaySoundEffect(sounds,&game_volume,SFX_HIT_INDUSTRUCTIBLE_BLOCK); } else { if(b->velocity.vx>0 && b->screen.vy+(b->h>>1)>p->screen.vy && b->screen.vy+(b->h>>1)screen.vy+p->h && b->screen.vx+b->w>p->screen.vx && b->screen.vx+b->wscreen.vx+p->w) { // Bloke has hit left of moving platform b->screen.vx=p->screen.vx-b->w; b->position.vx=b->screen.vx<velocity.vx=-b->velocity.vx; PlaySoundEffect(sounds,&game_volume,SFX_HIT_INDUSTRUCTIBLE_BLOCK); } } } } } void HandleMoveBlokeEffect(OBJECT *o) { long x,y; //if(o->timer) //{ // o->timer--; //if(bat->type.s.current_frame==BAT_LEFT) // x=bat->screen.vx<screen.vx+bat->w<screen.vx+(bat->w>>1))<screen.vy+bat->h-6)<velocity.vx=(x-o->position.vx)/15; o->velocity.vy=(y-o->position.vy)/8; if(!FadeObjectBrightness(o,&brightness[GAME_MIN_BRIGHTNESS],10<type.p.type_code=PTILE; o->type.p.type.ptile.w=(rand()%2)+1; o->type.p.type.ptile.h=(rand()%2)+1; o->type.p.type.ptile.attribute=TRANSPARENCY_ON|BG_PLUS_SP; SetObjectsBrightness(o,&brightness[GAME_MOVE_BLOKE_BRIGHTNESS+i]); SetObjectsOtOffset(o,0); x=-3+((rand()%6)+1); y=(rand()%6)+1; SetObjectsPosition(o,b->screen.vx+(b->w>>1)+x,b->screen.vy+b->h+y,0); o->parent=b; } } } void HandleBeamObject(OBJECT *o) { o->type.gsl2.x0=bat->screen.vx+(bat->w>>1); o->type.gsl2.y0=bat->screen.vy+bat->h; o->type.gsl2.x1=bloke->screen.vx+(bloke->w>>1); o->type.gsl2.y1=bloke->screen.vy+bloke->h; } // Function : HandleLevelObject() // Coded by : Scott Evans // Created/Modified : 1/7/98 // Description : Handles the bonus level message // Parameters : o - pointer to object // Returns : None // Notes : None void HandleLevelObject(OBJECT *o) { //if(o->screen.vy>-32 && !o->extra[0]) //{ //FadeObjectBrightness(o,&brightness[0],30<timer) { o->timer--; } if(o->extra[0]) { if(o->timer && o->screen.vy>((GAME_SCREEN_H-o->h)>>1)+22) { o->velocity.vy=-5<screen.vy=((GAME_SCREEN_H-o->h)>>1)+22; o->position.vx=o->screen.vx<timer && o->screen.vy>((GAME_SCREEN_H-o->h)>>1)+20) { o->velocity.vy=-5<screen.vy=((GAME_SCREEN_H-o->h)>>1)+20; o->position.vx=o->screen.vx<screen.vy>GAME_SCREEN_H+20) { RemoveObjectFromList(&objects_list,o); gd.lspr_clear=0; } } void HandleEmptyBlockCounter(OBJECT *o) { OBJECT *b; static long block_vx[]={2*FPN24_8,2.5*FPN24_8,3.0*FPN24_8,3.5*FPN24_8,4.0*FPN24_8,4.5*FPN24_8}; o->timer++; if(o->tmp) { // Stop it flashing block_counter->type.bar.bar->blink=0; block_counter->type.bar.bar->visible=1; if(!(o->timer%3)) { PlaySoundEffect(sounds,&game_volume,SFX_FIREGUN); o->tmp--; if(gd.block_sp>0) gd.block_sp--; b=CreateBlockSprite(3,18,gd.block_stack[gd.block_sp]); SetObjectsVelocity(b,0,-2,0); SetObjectsAcceleration(b,0,0.2,0); b->velocity.vx=-(block_vx[rand()%6]); b->extra[0]=1; b->extra[1]=0; } } else RemoveObjectFromList(&objects_list,o); }