-
Notifications
You must be signed in to change notification settings - Fork 0
/
seeker.cp
5116 lines (4738 loc) · 210 KB
/
seeker.cp
1
/****************************************************************************************//* SEEKER.CP *//****************************************************************************************//* (c) 1995 by Magnet Interactive Studios, inc. All rights reserved. *//****************************************************************************************//* Revision History: *//* v5.6 5/5/95 Icebreaker Golden Master version. By Andrew Looney. *//* v6.1 8/21/95 Began making changes for Icebreaker Two. By Andrew Looney. *//* v6.4 4/23/96 Optimized ScottyEnergize(). By Andrew Looney. *//****************************************************************************************//***************************** WHAT THIS SOFTWARE DOES ********************************** This function implements a special type of object called a seeker. In the context of the game Icebreaker, a seeker is a "living" pyramid that always tries to move towards the center of the screen (i.e. towards the dudemeyer) and which is deadly to the dudemeyer ifit catches it. Some seekers are stupid and will wait behind obstacles until the dudemeyerhas moved enough to allow an open, direct path; others are smarter and can maneuveraround obstacles. There are different routines in this class that implement differentlevels of intelligence for different types of seekers. In Icebreaker, there are a set number of seekers on each level, and anytime one isdestroyed, a new one replaces it, until such time as all other pyramids are eliminated.At that point, the seekers can be permanently eliminated. *****************************************************************************************//***** includes (make sure CPlusSwiHack.h is the last one) *****/#include "graphics.h"#include "stdio.h"#include "stdlib.h"#include "mem.h"#include "types.h"#include "hardware.h"#include "event.h"#include "strings.h"#include "access.h"#include "UMemory.h"#include "Form3DO.h"#include "Init3DO.h"#include "Parse3DO.h"#include "Utils3DO.h"#include "audio.h"#include "music.h"/***** Magnet includes *****/#include "icebreaker.h"#include "animation.h"#include "landscape.h"#include "solids.h"#include "sounds.h"#include "seeker.h"#include "deadlist.h"#include "dudemeyer.h"#include "weapon.h"/***** special c++ include (this must be last) *****/#include "CPlusSwiHack.h"/***** global variables *****/extern int32 g_total_pyramids;extern int32 g_dead;extern bool g_art_usage[TOTAL_ART_ELEMENTS];extern bool pac_mid,easter_lurker;extern int32 level_lookup_table [ROWS_IN_LANDSCAPE] [COLUMNS_IN_LANDSCAPE];/***** global class instantiations *****/extern landscape pavement;extern solids population;extern dudemeyer icebreaker;extern dead_list morgue;extern weapon fireball;/****************************** seeker::BootSeekers *********************************** This function simply sets all of the artwork element pointer values to NULL. This isimportant because artwork is only loaded if the pointer is set to NULL, and on bootup wecan't really be certain that these pointers will be pre-initialized to the value NULL.*****************************************************************************************/void seeker::BootSeekers (void) { yellow_piece_cel = (CCB *) NULL; yellow_walk_e.anim_pointer = (ANIM *) NULL; yellow_walk_w.anim_pointer = (ANIM *) NULL; yellow_walk_n.anim_pointer = (ANIM *) NULL; yellow_walk_s.anim_pointer = (ANIM *) NULL; yellow_walk_ne.anim_pointer = (ANIM *) NULL; yellow_walk_nw.anim_pointer = (ANIM *) NULL; yellow_walk_se.anim_pointer = (ANIM *) NULL; yellow_walk_sw.anim_pointer = (ANIM *) NULL; yellow_pit_death.anim_pointer = (ANIM *) NULL; yellow_lava_death.anim_pointer = (ANIM *) NULL; yellow_death.anim_pointer = (ANIM *) NULL; ltblue_piece_cel = (CCB *) NULL; ltblue_walk_e.anim_pointer = (ANIM *) NULL; ltblue_walk_w.anim_pointer = (ANIM *) NULL; ltblue_walk_n.anim_pointer = (ANIM *) NULL; ltblue_walk_s.anim_pointer = (ANIM *) NULL; ltblue_walk_ne.anim_pointer = (ANIM *) NULL; ltblue_walk_nw.anim_pointer = (ANIM *) NULL; ltblue_walk_se.anim_pointer = (ANIM *) NULL; ltblue_walk_sw.anim_pointer = (ANIM *) NULL; ltblue_pit_death.anim_pointer = (ANIM *) NULL; ltblue_lava_death.anim_pointer = (ANIM *) NULL; ltblue_death.anim_pointer = (ANIM *) NULL; pink_piece_cel = (CCB *) NULL; pink_walk_e.anim_pointer = (ANIM *) NULL; pink_walk_w.anim_pointer = (ANIM *) NULL; pink_walk_n.anim_pointer = (ANIM *) NULL; pink_walk_s.anim_pointer = (ANIM *) NULL; pink_walk_ne.anim_pointer = (ANIM *) NULL; pink_walk_nw.anim_pointer = (ANIM *) NULL; pink_walk_se.anim_pointer = (ANIM *) NULL; pink_walk_sw.anim_pointer = (ANIM *) NULL; pink_pit_death.anim_pointer = (ANIM *) NULL; pink_lava_death.anim_pointer = (ANIM *) NULL; pink_death.anim_pointer = (ANIM *) NULL; lime_piece_cel = (CCB *) NULL; lime_walk_e.anim_pointer = (ANIM *) NULL; lime_walk_w.anim_pointer = (ANIM *) NULL; lime_walk_n.anim_pointer = (ANIM *) NULL; lime_walk_s.anim_pointer = (ANIM *) NULL; lime_walk_ne.anim_pointer = (ANIM *) NULL; lime_walk_nw.anim_pointer = (ANIM *) NULL; lime_walk_se.anim_pointer = (ANIM *) NULL; lime_walk_sw.anim_pointer = (ANIM *) NULL; lime_death_e.anim_pointer = (ANIM *) NULL; lime_death_w.anim_pointer = (ANIM *) NULL; lime_death_s.anim_pointer = (ANIM *) NULL; lime_death_n.anim_pointer = (ANIM *) NULL; lime_pit_death.anim_pointer = (ANIM *) NULL; lime_lava_death.anim_pointer = (ANIM *) NULL; lime_still.anim_pointer = (ANIM *) NULL; zombie1_walk_e.anim_pointer = (ANIM *) NULL; zombie1_walk_w.anim_pointer = (ANIM *) NULL; zombie1_walk_n.anim_pointer = (ANIM *) NULL; zombie1_walk_s.anim_pointer = (ANIM *) NULL; zombie1_walk_ne.anim_pointer = (ANIM *) NULL; zombie1_walk_nw.anim_pointer = (ANIM *) NULL; zombie1_walk_se.anim_pointer = (ANIM *) NULL; zombie1_walk_sw.anim_pointer = (ANIM *) NULL; zombie2_walk_e.anim_pointer = (ANIM *) NULL; zombie2_walk_w.anim_pointer = (ANIM *) NULL; zombie2_walk_n.anim_pointer = (ANIM *) NULL; zombie2_walk_s.anim_pointer = (ANIM *) NULL; zombie2_walk_ne.anim_pointer = (ANIM *) NULL; zombie2_walk_nw.anim_pointer = (ANIM *) NULL; zombie2_walk_se.anim_pointer = (ANIM *) NULL; zombie2_walk_sw.anim_pointer = (ANIM *) NULL; zombie3_walk_e.anim_pointer = (ANIM *) NULL; zombie3_walk_w.anim_pointer = (ANIM *) NULL; zombie3_walk_n.anim_pointer = (ANIM *) NULL; zombie3_walk_s.anim_pointer = (ANIM *) NULL; zombie3_walk_ne.anim_pointer = (ANIM *) NULL; zombie3_walk_nw.anim_pointer = (ANIM *) NULL; zombie3_walk_se.anim_pointer = (ANIM *) NULL; zombie3_walk_sw.anim_pointer = (ANIM *) NULL; zombie1pit_death.anim_pointer = (ANIM *) NULL; zombie2pit_death.anim_pointer = (ANIM *) NULL; zombie3pit_death.anim_pointer = (ANIM *) NULL; zombie1lava_death.anim_pointer = (ANIM *) NULL; zombie2lava_death.anim_pointer = (ANIM *) NULL; zombie3lava_death.anim_pointer = (ANIM *) NULL; zombie_death.anim_pointer = (ANIM *) NULL; zombie_birth.anim_pointer = (ANIM *) NULL; zombie_shrapnel.anim_pointer = (ANIM *) NULL; cham_wakeup_anim.anim_pointer = (ANIM *) NULL; cham_death_e.anim_pointer = (ANIM *) NULL; cham_death_w.anim_pointer = (ANIM *) NULL; cham_death_n.anim_pointer = (ANIM *) NULL; cham_death_s.anim_pointer = (ANIM *) NULL; redcoat_wakeup_anim.anim_pointer= (ANIM *) NULL; redcoat_death_e.anim_pointer = (ANIM *) NULL; redcoat_death_w.anim_pointer = (ANIM *) NULL; redcoat_death_n.anim_pointer = (ANIM *) NULL; redcoat_death_s.anim_pointer = (ANIM *) NULL; bummer_wakeup_anim.anim_pointer= (ANIM *) NULL; bummer_death.anim_pointer = (ANIM *) NULL; lurker_walk_e.anim_pointer = (ANIM *) NULL; lurker_walk_w.anim_pointer = (ANIM *) NULL; lurker_walk_n.anim_pointer = (ANIM *) NULL; lurker_walk_s.anim_pointer = (ANIM *) NULL; lurker_walk_ne.anim_pointer = (ANIM *) NULL; lurker_walk_nw.anim_pointer = (ANIM *) NULL; lurker_walk_se.anim_pointer = (ANIM *) NULL; lurker_walk_sw.anim_pointer = (ANIM *) NULL; lurker_pit_death.anim_pointer = (ANIM *) NULL; lurker_lava_death.anim_pointer = (ANIM *) NULL; lurker_wait.anim_pointer = (ANIM *) NULL; lurker_death_e.anim_pointer = (ANIM *) NULL; lurker_death_w.anim_pointer = (ANIM *) NULL; lurker_death_s.anim_pointer = (ANIM *) NULL; lurker_death_n.anim_pointer = (ANIM *) NULL; lurker_piece_cel = (CCB *) NULL; meany_walk_e_w_n_s.anim_pointer= (ANIM *) NULL; meany_walk_se_nw.anim_pointer = (ANIM *) NULL; meany_walk_ne_sw.anim_pointer = (ANIM *) NULL; meany_pit_death.anim_pointer = (ANIM *) NULL; meany_lava_death.anim_pointer = (ANIM *) NULL; meany_split.anim_pointer = (ANIM *) NULL; meany_split_n.anim_pointer = (ANIM *) NULL; meany_split_s.anim_pointer = (ANIM *) NULL; meany_split_e.anim_pointer = (ANIM *) NULL; meany_split_w.anim_pointer = (ANIM *) NULL; meany_stasis.anim_pointer = (ANIM *) NULL; nasty_walk_e_w_n_s.anim_pointer= (ANIM *) NULL; nasty_walk_se_nw.anim_pointer = (ANIM *) NULL; nasty_walk_ne_sw.anim_pointer = (ANIM *) NULL; nasty_pit_death.anim_pointer = (ANIM *) NULL; nasty_lava_death.anim_pointer = (ANIM *) NULL; nasty_split.anim_pointer = (ANIM *) NULL; nasty_split_n.anim_pointer = (ANIM *) NULL; nasty_split_s.anim_pointer = (ANIM *) NULL; nasty_split_e.anim_pointer = (ANIM *) NULL; nasty_split_w.anim_pointer = (ANIM *) NULL; nasty_stasis.anim_pointer = (ANIM *) NULL; grumpy_walk_e_w_n_s.anim_pointer= (ANIM *) NULL; grumpy_walk_se_nw.anim_pointer = (ANIM *) NULL; grumpy_walk_ne_sw.anim_pointer = (ANIM *) NULL; grumpy_pit_death.anim_pointer = (ANIM *) NULL; grumpy_lava_death.anim_pointer = (ANIM *) NULL; grumpy_death.anim_pointer = (ANIM *) NULL; jugger_walk_e.anim_pointer = (ANIM *) NULL; jugger_walk_w.anim_pointer = (ANIM *) NULL; jugger_walk_n.anim_pointer = (ANIM *) NULL; jugger_walk_s.anim_pointer = (ANIM *) NULL; jugger_walk_ne.anim_pointer = (ANIM *) NULL; jugger_walk_nw.anim_pointer = (ANIM *) NULL; jugger_walk_se.anim_pointer = (ANIM *) NULL; jugger_walk_sw.anim_pointer = (ANIM *) NULL; jugger_pit_death.anim_pointer = (ANIM *) NULL; jugger_lava_death.anim_pointer = (ANIM *) NULL; jugger_death.anim_pointer = (ANIM *) NULL; psycho_walk_e.anim_pointer = (ANIM *) NULL; psycho_walk_w.anim_pointer = (ANIM *) NULL; psycho_walk_n.anim_pointer = (ANIM *) NULL; psycho_walk_s.anim_pointer = (ANIM *) NULL; psycho_walk_ne.anim_pointer = (ANIM *) NULL; psycho_walk_nw.anim_pointer = (ANIM *) NULL; psycho_walk_se.anim_pointer = (ANIM *) NULL; psycho_walk_sw.anim_pointer = (ANIM *) NULL; psycho_pit_death.anim_pointer = (ANIM *) NULL; psycho_lava_death.anim_pointer = (ANIM *) NULL; psycho_unmoving.anim_pointer = (ANIM *) NULL; psycho_death[0].anim_pointer = (ANIM *) NULL; psycho_death[1].anim_pointer = (ANIM *) NULL; psycho_death[2].anim_pointer = (ANIM *) NULL; beam_in_part1.anim_pointer = (ANIM *) NULL; beam_in_part2.anim_pointer = (ANIM *) NULL;}/****************************** seeker::LoadArtwork *********************************** This function is called whenever the software determines that it needs a given artworkelement but that this element has not been loaded into memory (i.e. the pointer to thatelement is set to NULL.) This function takes as input the symbol which uniquely identifiesthis piece of artwork, and loads it into memory. If the file could not be found, thisfunction calls the routine ArtworkMissing, which will identify the missing art and abortthe program. (It is assumed that such problems will occur only during testing.) Note that in this class, the artwork element to be loaded here is really a whole seriesof artwork elements, i.e. all of the different pieces of art that may be needed for thehandling of a given type of seeker.*****************************************************************************************/void seeker::LoadArtwork (int32 element_to_load){ switch(element_to_load) { case YELLOW_SEEKER: yellow_piece_cel = LoadCel(YELLOW_PIECE_FILE,MEMTYPE_CEL); if (yellow_piece_cel == NULL) ArtworkMissing(YELLOW_SEEKER); if ((!(yellow_walk_e.LoadArtwork (YELLOW_WALK_EAST))) || (!(yellow_walk_w.LoadArtwork (YELLOW_WALK_WEST))) || (!(yellow_walk_n.LoadArtwork (YELLOW_WALK_NORTH))) || (!(yellow_walk_s.LoadArtwork (YELLOW_WALK_SOUTH))) || (!(yellow_walk_ne.LoadArtwork (YELLOW_WALK_NE))) || (!(yellow_walk_nw.LoadArtwork (YELLOW_WALK_NW))) || (!(yellow_walk_se.LoadArtwork (YELLOW_WALK_SE))) || (!(yellow_walk_sw.LoadArtwork (YELLOW_WALK_SW))) || (!(yellow_pit_death.LoadArtwork (YELLOW_PIT_ANIM))) || (!(yellow_lava_death.LoadArtwork (YELLOW_LAVA_ANIM))) || (!(yellow_death.LoadArtwork (YELLOW_DEATH_ANIM)))) ArtworkMissing(YELLOW_SEEKER); break; case DORMANT_BUMMER: if ((!(bummer_wakeup_anim.LoadArtwork(BUMMER_WAKEUP_ANIM))) || (!(bummer_death.LoadArtwork (BUMMER_DEATH_ANIM)))) ArtworkMissing(DORMANT_BUMMER); if (ltblue_piece_cel != NULL) break; case LTBLUE_SEEKER: ltblue_piece_cel = LoadCel(LTBLUE_PIECE_FILE,MEMTYPE_CEL); if (ltblue_piece_cel == NULL) ArtworkMissing(LTBLUE_SEEKER); if ((!(ltblue_walk_e.LoadArtwork (LTBLUE_WALK_EAST))) || (!(ltblue_walk_w.LoadArtwork (LTBLUE_WALK_WEST))) || (!(ltblue_walk_n.LoadArtwork (LTBLUE_WALK_NORTH))) || (!(ltblue_walk_s.LoadArtwork (LTBLUE_WALK_SOUTH))) || (!(ltblue_walk_ne.LoadArtwork (LTBLUE_WALK_NE))) || (!(ltblue_walk_nw.LoadArtwork (LTBLUE_WALK_NW))) || (!(ltblue_walk_se.LoadArtwork (LTBLUE_WALK_SE))) || (!(ltblue_walk_sw.LoadArtwork (LTBLUE_WALK_SW))) || (!(ltblue_pit_death.LoadArtwork (LTBLUE_PIT_ANIM))) || (!(ltblue_lava_death.LoadArtwork (LTBLUE_LAVA_ANIM))) || (!(ltblue_death.LoadArtwork (LTBLUE_DEATH_ANIM)))) ArtworkMissing(LTBLUE_SEEKER); break; case PINK_SEEKER: pink_piece_cel = LoadCel(PINK_PIECE_FILE, MEMTYPE_CEL); if (pink_piece_cel == NULL) ArtworkMissing(PINK_SEEKER); if ((!(pink_walk_e.LoadArtwork (PINK_WALK_EAST))) || (!(pink_walk_w.LoadArtwork (PINK_WALK_WEST))) || (!(pink_walk_n.LoadArtwork (PINK_WALK_NORTH))) || (!(pink_walk_s.LoadArtwork (PINK_WALK_SOUTH))) || (!(pink_walk_ne.LoadArtwork (PINK_WALK_NE))) || (!(pink_walk_nw.LoadArtwork (PINK_WALK_NW))) || (!(pink_walk_se.LoadArtwork (PINK_WALK_SE))) || (!(pink_walk_sw.LoadArtwork (PINK_WALK_SW))) || (!(pink_pit_death.LoadArtwork (PINK_PIT_ANIM))) || (!(pink_lava_death.LoadArtwork (PINK_LAVA_ANIM))) || (!(pink_death.LoadArtwork (PINK_DEATH_ANIM)))) ArtworkMissing(PINK_SEEKER); break; case DORMANT_CHAMELEON: if ((!(cham_wakeup_anim.LoadArtwork (CHAM_WAKEUP_ANIM))) || (!(cham_death_e.LoadArtwork (CHAM_DEATH_E))) || (!(cham_death_w.LoadArtwork (CHAM_DEATH_W))) || (!(cham_death_n.LoadArtwork (CHAM_DEATH_N))) || (!(cham_death_s.LoadArtwork (CHAM_DEATH_S)))) ArtworkMissing(DORMANT_CHAMELEON); if (lime_piece_cel != NULL) break; case LIME_SEEKER: if (pac_mid) { lime_piece_cel = LoadCel(PACMID_PIECE_FILE,MEMTYPE_CEL); if (lime_piece_cel == NULL) ArtworkMissing(LIME_SEEKER); if ((!(lime_pit_death.LoadArtwork (PACMID_PIT_ANIM))) || (!(lime_walk_e.LoadArtwork (PACMID_WALK_EAST))) || (!(lime_walk_w.LoadArtwork (PACMID_WALK_WEST))) || (!(lime_walk_n.LoadArtwork (PACMID_WALK_NORTH))) || (!(lime_walk_s.LoadArtwork (PACMID_WALK_SOUTH))) || (!(lime_walk_ne.LoadArtwork (PACMID_WALK_NE))) || (!(lime_walk_nw.LoadArtwork (PACMID_WALK_NW))) || (!(lime_walk_se.LoadArtwork (PACMID_WALK_SE))) || (!(lime_walk_sw.LoadArtwork (PACMID_WALK_SW))) || (!(lime_death_e.LoadArtwork (PACMID_DEATH_E))) || (!(lime_death_w.LoadArtwork (PACMID_DEATH_W))) || (!(lime_death_s.LoadArtwork (PACMID_DEATH_S))) || (!(lime_death_n.LoadArtwork (PACMID_DEATH_N))) || (!(lime_still.LoadArtwork (PACMID_STILL))) || (!(lime_lava_death.LoadArtwork (PACMID_LAVA_ANIM)))) ArtworkMissing(LIME_SEEKER); } else { lime_piece_cel = LoadCel(LIME_PIECE_FILE, MEMTYPE_CEL); if (lime_piece_cel == NULL) ArtworkMissing(LIME_SEEKER); if ((!(lime_pit_death.LoadArtwork (LIME_PIT_ANIM))) || (!(lime_walk_e.LoadArtwork (LIME_WALK_EAST))) || (!(lime_walk_w.LoadArtwork (LIME_WALK_WEST))) || (!(lime_walk_n.LoadArtwork (LIME_WALK_NORTH))) || (!(lime_walk_s.LoadArtwork (LIME_WALK_SOUTH))) || (!(lime_walk_ne.LoadArtwork (LIME_WALK_NE))) || (!(lime_walk_nw.LoadArtwork (LIME_WALK_NW))) || (!(lime_walk_se.LoadArtwork (LIME_WALK_SE))) || (!(lime_walk_sw.LoadArtwork (LIME_WALK_SW))) || (!(lime_death_e.LoadArtwork (LIME_DEATH_E))) || (!(lime_death_w.LoadArtwork (LIME_DEATH_W))) || (!(lime_death_s.LoadArtwork (LIME_DEATH_S))) || (!(lime_death_n.LoadArtwork (LIME_DEATH_N))) || (!(lime_still.LoadArtwork (LIME_STILL))) || (!(lime_lava_death.LoadArtwork (LIME_LAVA_ANIM)))) ArtworkMissing(LIME_SEEKER); } break; case DORMANT_REDCOAT: if((!(redcoat_wakeup_anim.LoadArtwork(REDCOAT_WAKEUP_ANIM))) || (!(redcoat_death_e.LoadArtwork (REDCOAT_DEATH_E))) || (!(redcoat_death_w.LoadArtwork (REDCOAT_DEATH_W))) || (!(redcoat_death_n.LoadArtwork (REDCOAT_DEATH_N))) || (!(redcoat_death_s.LoadArtwork (REDCOAT_DEATH_S)))) ArtworkMissing(DORMANT_REDCOAT); if (lurker_piece_cel != NULL) break; case LURKER: if (easter_lurker) { if ((!(lurker_walk_e.LoadArtwork (EGG_WALK_EAST))) || (!(lurker_walk_w.LoadArtwork (EGG_WALK_WEST))) || (!(lurker_walk_n.LoadArtwork (EGG_WALK_NORTH))) || (!(lurker_walk_s.LoadArtwork (EGG_WALK_SOUTH))) || (!(lurker_walk_ne.LoadArtwork (EGG_WALK_NE))) || (!(lurker_walk_nw.LoadArtwork (EGG_WALK_NW))) || (!(lurker_walk_se.LoadArtwork (EGG_WALK_SE))) || (!(lurker_walk_sw.LoadArtwork (EGG_WALK_SW))) || (!(lurker_pit_death.LoadArtwork (EGG_PIT_ANIM))) || (!(lurker_lava_death.LoadArtwork(EGG_LAVA_ANIM))) || (!(lurker_death_e.LoadArtwork (EGG_DEATH_E))) || (!(lurker_death_w.LoadArtwork (EGG_DEATH_W))) || (!(lurker_death_s.LoadArtwork (EGG_DEATH_S))) || (!(lurker_death_n.LoadArtwork (EGG_DEATH_N))) || (!(lurker_wait.LoadArtwork (EGG_WAIT_ANIM)))) ArtworkMissing(LURKER); lurker_piece_cel=LoadCel(EGG_PIECE_FILE,MEMTYPE_CEL); if (lurker_piece_cel == NULL) ArtworkMissing(LURKER); } else { if ((!(lurker_walk_e.LoadArtwork (LURKER_WALK_EAST))) || (!(lurker_walk_w.LoadArtwork (LURKER_WALK_WEST))) || (!(lurker_walk_n.LoadArtwork (LURKER_WALK_NORTH))) || (!(lurker_walk_s.LoadArtwork (LURKER_WALK_SOUTH))) || (!(lurker_walk_ne.LoadArtwork (LURKER_WALK_NE))) || (!(lurker_walk_nw.LoadArtwork (LURKER_WALK_NW))) || (!(lurker_walk_se.LoadArtwork (LURKER_WALK_SE))) || (!(lurker_walk_sw.LoadArtwork (LURKER_WALK_SW))) || (!(lurker_pit_death.LoadArtwork (LURKER_PIT_ANIM))) || (!(lurker_lava_death.LoadArtwork(LURKER_LAVA_ANIM))) || (!(lurker_death_e.LoadArtwork (LURKER_DEATH_E))) || (!(lurker_death_w.LoadArtwork (LURKER_DEATH_W))) || (!(lurker_death_s.LoadArtwork (LURKER_DEATH_S))) || (!(lurker_death_n.LoadArtwork (LURKER_DEATH_N))) || (!(lurker_wait.LoadArtwork (LURKER_WAIT_ANIM)))) ArtworkMissing(LURKER); lurker_piece_cel=LoadCel(LURKER_PIECE_FILE,MEMTYPE_CEL); if (lurker_piece_cel == NULL) ArtworkMissing(LURKER); } break; case ZOMBIE: if ((!(zombie_shrapnel.LoadArtwork (ZOMBIE_SHRAPNEL_ANIM))) || (!(zombie_death.LoadArtwork (ZOMBIE_DEATH_ANIM))) || (!(zombie_birth.LoadArtwork (ZOMBIE_BIRTH_ANIM))) || (!(zombie1_walk_e.LoadArtwork (ZOMBIE1_WALK_EAST))) || (!(zombie1_walk_w.LoadArtwork (ZOMBIE1_WALK_WEST))) || (!(zombie1_walk_n.LoadArtwork (ZOMBIE1_WALK_NORTH))) || (!(zombie1_walk_s.LoadArtwork (ZOMBIE1_WALK_SOUTH))) || (!(zombie1_walk_ne.LoadArtwork (ZOMBIE1_WALK_NE))) || (!(zombie1_walk_nw.LoadArtwork (ZOMBIE1_WALK_NW))) || (!(zombie1_walk_se.LoadArtwork (ZOMBIE1_WALK_SE))) || (!(zombie1_walk_sw.LoadArtwork (ZOMBIE1_WALK_SW))) || (!(zombie2_walk_e.LoadArtwork (ZOMBIE2_WALK_EAST))) || (!(zombie2_walk_w.LoadArtwork (ZOMBIE2_WALK_WEST))) || (!(zombie2_walk_n.LoadArtwork (ZOMBIE2_WALK_NORTH))) || (!(zombie2_walk_s.LoadArtwork (ZOMBIE2_WALK_SOUTH))) || (!(zombie2_walk_ne.LoadArtwork (ZOMBIE2_WALK_NE))) || (!(zombie2_walk_nw.LoadArtwork (ZOMBIE2_WALK_NW))) || (!(zombie2_walk_se.LoadArtwork (ZOMBIE2_WALK_SE))) || (!(zombie2_walk_sw.LoadArtwork (ZOMBIE2_WALK_SW))) || (!(zombie3_walk_e.LoadArtwork (ZOMBIE3_WALK_EAST))) || (!(zombie3_walk_w.LoadArtwork (ZOMBIE3_WALK_WEST))) || (!(zombie3_walk_n.LoadArtwork (ZOMBIE3_WALK_NORTH))) || (!(zombie3_walk_s.LoadArtwork (ZOMBIE3_WALK_SOUTH))) || (!(zombie3_walk_ne.LoadArtwork (ZOMBIE3_WALK_NE))) || (!(zombie3_walk_nw.LoadArtwork (ZOMBIE3_WALK_NW))) || (!(zombie3_walk_se.LoadArtwork (ZOMBIE3_WALK_SE))) || (!(zombie3_walk_sw.LoadArtwork (ZOMBIE3_WALK_SW))) || (!(zombie1pit_death.LoadArtwork (ZOMBIE1_PIT_ANIM))) || (!(zombie2pit_death.LoadArtwork (ZOMBIE2_PIT_ANIM))) || (!(zombie3pit_death.LoadArtwork (ZOMBIE3_PIT_ANIM))) || (!(zombie1lava_death.LoadArtwork (ZOMBIE1_LAVA_ANIM))) || (!(zombie2lava_death.LoadArtwork (ZOMBIE2_LAVA_ANIM))) || (!(zombie3lava_death.LoadArtwork (ZOMBIE3_LAVA_ANIM)))) ArtworkMissing(ZOMBIE); break; case MEANY: if ((!(meany_walk_e_w_n_s.LoadArtwork (MEANY_WALK_E_W_N_S))) || (!(meany_walk_se_nw.LoadArtwork (MEANY_WALK_NE_SW))) || (!(meany_walk_ne_sw.LoadArtwork (MEANY_WALK_SE_NW))) || (!(meany_pit_death.LoadArtwork (MEANY_PIT_ANIM))) || (!(meany_lava_death.LoadArtwork (MEANY_LAVA_ANIM))) || (!(meany_split.LoadArtwork (MEANY_SPLIT_ANIM))) || (!(meany_split_n.LoadArtwork (MEANY_SPLIT_N_ANIM))) || (!(meany_split_s.LoadArtwork (MEANY_SPLIT_S_ANIM))) || (!(meany_split_e.LoadArtwork (MEANY_SPLIT_E_ANIM))) || (!(meany_split_w.LoadArtwork (MEANY_SPLIT_W_ANIM))) || (!(meany_stasis.LoadArtwork (MEANY_STASIS_ANIM)))) ArtworkMissing(MEANY); case NASTY: if ((!(nasty_walk_e_w_n_s.LoadArtwork (NASTY_WALK_E_W_N_S))) || (!(nasty_walk_se_nw.LoadArtwork (NASTY_WALK_NE_SW))) || (!(nasty_walk_ne_sw.LoadArtwork (NASTY_WALK_SE_NW))) || (!(nasty_pit_death.LoadArtwork (NASTY_PIT_ANIM))) || (!(nasty_lava_death.LoadArtwork (NASTY_LAVA_ANIM))) || (!(nasty_split.LoadArtwork (NASTY_SPLIT_ANIM))) || (!(nasty_split_n.LoadArtwork (NASTY_SPLIT_N_ANIM))) || (!(nasty_split_s.LoadArtwork (NASTY_SPLIT_S_ANIM))) || (!(nasty_split_e.LoadArtwork (NASTY_SPLIT_E_ANIM))) || (!(nasty_split_w.LoadArtwork (NASTY_SPLIT_W_ANIM))) || (!(nasty_stasis.LoadArtwork (NASTY_STASIS_ANIM)))) ArtworkMissing(NASTY); case GRUMPY: if ((!(grumpy_walk_e_w_n_s.LoadArtwork(GRUMPY_WALK_E_W_N_S))) || (!(grumpy_walk_se_nw.LoadArtwork (GRUMPY_WALK_NE_SW))) || (!(grumpy_walk_ne_sw.LoadArtwork (GRUMPY_WALK_SE_NW))) || (!(grumpy_pit_death.LoadArtwork (GRUMPY_PIT_ANIM))) || (!(grumpy_lava_death.LoadArtwork (GRUMPY_LAVA_ANIM))) || (!(grumpy_death.LoadArtwork (GRUMPY_DEATH_ANIM)))) ArtworkMissing(GRUMPY); break; case JUGGERNAUT: if ((!(jugger_walk_e.LoadArtwork (JUGGERNAUT_WALK_EAST))) || (!(jugger_walk_w.LoadArtwork (JUGGERNAUT_WALK_WEST))) || (!(jugger_walk_n.LoadArtwork (JUGGERNAUT_WALK_NORTH))) || (!(jugger_walk_s.LoadArtwork (JUGGERNAUT_WALK_SOUTH))) || (!(jugger_walk_ne.LoadArtwork (JUGGERNAUT_WALK_NE))) || (!(jugger_walk_nw.LoadArtwork (JUGGERNAUT_WALK_NW))) || (!(jugger_walk_se.LoadArtwork (JUGGERNAUT_WALK_SE))) || (!(jugger_walk_sw.LoadArtwork (JUGGERNAUT_WALK_SW))) || (!(jugger_pit_death.LoadArtwork (JUGGERNAUT_PIT_ANIM))) || (!(jugger_lava_death.LoadArtwork(JUGGERNAUT_LAVA_ANIM))) || (!(jugger_death.LoadArtwork (JUGGERNAUT_DEATH_ANIM)))) ArtworkMissing(JUGGERNAUT); break; case PSYCHO: if ((!(psycho_walk_e.LoadArtwork (PSYCHO_WALK_EAST))) || (!(psycho_walk_w.LoadArtwork (PSYCHO_WALK_WEST))) || (!(psycho_walk_n.LoadArtwork (PSYCHO_WALK_NORTH))) || (!(psycho_walk_s.LoadArtwork (PSYCHO_WALK_SOUTH))) || (!(psycho_walk_ne.LoadArtwork (PSYCHO_WALK_NE))) || (!(psycho_walk_nw.LoadArtwork (PSYCHO_WALK_NW))) || (!(psycho_walk_se.LoadArtwork (PSYCHO_WALK_SE))) || (!(psycho_walk_sw.LoadArtwork (PSYCHO_WALK_SW))) || (!(psycho_pit_death.LoadArtwork (PSYCHO_PIT_ANIM))) || (!(psycho_lava_death.LoadArtwork(PSYCHO_LAVA_ANIM))) || (!(psycho_unmoving.LoadArtwork(PSYCHO_STILL_ANIM))) || (!(psycho_death[0].LoadArtwork (LTBLUE_DEATH_ANIM))) || (!(psycho_death[1].LoadArtwork (YELLOW_DEATH_ANIM))) || (!(psycho_death[2].LoadArtwork (PINK_DEATH_ANIM)))) ArtworkMissing(PSYCHO); break; case SEEKER_MATERIALIZATION: if ((!(beam_in_part1.LoadArtwork (SEEKER_BEAM_IN_1))) || (!(beam_in_part2.LoadArtwork (SEEKER_BEAM_IN_2)))) ArtworkMissing(SEEKER_MATERIALIZATION); break; }}/*************************** seeker::SetSeekerSpeeds ********************************** This function sets a seeker's movement speed values to their initial states. It isused both during initialization and as needed during the game to reset speed to normal.*****************************************************************************************/void seeker::SetSeekerSpeeds(register dude *target){ switch (target->breed) { case YELLOW_SEEKER: case LTBLUE_SEEKER: case PINK_SEEKER: case LIME_SEEKER: case PSYCHO: case JUGGERNAUT: case DORMANT_BUMMER: case WAKING_BUMMER: case ACTIVE_BUMMER: case DORMANT_CHAMELEON: case WAKING_CHAMELEON: case ACTIVE_CHAMELEON: target->horz_speed = (3 << 16); target->vert_speed = (3 << 16); break; case ZOMBIE: target->horz_speed = (2 << 16); target->vert_speed = (2 << 16); break; case DORMANT_REDCOAT: case WAKING_REDCOAT: case ACTIVE_REDCOAT: case LURKER: target->horz_speed = (7 << 16); target->vert_speed = (5 << 16); break; case MEANY: target->horz_speed = 0x00025000; /* i.e. 2.5 */ target->vert_speed = 0x00025000; /* i.e. 2.5 */ break; case NASTY: target->horz_speed = 0x00030000; /* i.e. 3.0 */ target->vert_speed = 0x00030000; /* i.e. 3.0 */ break; case GRUMPY: target->horz_speed = 0x00035000; /* i.e. 3.5 */ target->vert_speed = 0x00035000; /* i.e. 3.5 */ break; }}/******************************* seeker::CreateSeeker ********************************* Since the number and type of seekers will vary from level to level, we keep track of them using a linked list. Whenever a new seeker is created (which will usually happen only at the beginning of a level) this function is called to grab some memory, use it to set up a record containing all needed information about the seeker, and then add that record to the linked list of seekers. Note that most information about the seeker that is needed at initialization time can be derived simply by knowing what kind of seeker it is. The exception to this is the seeker's home tile.*****************************************************************************************/dude* seeker::CreateSeeker (int32 breed, int32 row, int32 column, int32 offset, bool homeward_bound) { dude *new_dude; int32 i,j; dude *traversal_list; new_dude = new(dude); new_dude->breed = breed; new_dude->home_row = row; new_dude->home_column = column; new_dude->home_offset = offset; new_dude->health = NOT_DEAD; new_dude->blocker = (solid_object *) NULL; new_dude->last_hazard = (CCB *) NULL; new_dude->last_hazard_type = HARMLESS; new_dude->current_row = -1; new_dude->current_column = -1; new_dude->move_counter = 0; new_dude->stranded_counter = 0; new_dude->immobile_counter = 0; new_dude->reversal_counter = 0; new_dude->previous_x = 0; new_dude->previous_y = 0; new_dude->move_status = NORMAL_MOVEMENT; new_dude->direction = 0; new_dude->obstacle_detour_axis = NO_AXIS; new_dude->obstacle_detour_direction = NO_DIRECTION; new_dude->old_obstacle_detour_axis = NO_AXIS; new_dude->hazard_detour_axis = NO_AXIS; new_dude->hazard_detour_direction = NO_DIRECTION; new_dude->alternate_hazard_direction = NO_DIRECTION; new_dude->bogged_down_in_swamp = 0; new_dude->special_anim.current_frame_ccb = (CCB *) NULL; if (g_art_usage[SEEKER_MATERIALIZATION] == TRUE) { if (beam_in_part1.anim_pointer == NULL) LoadArtwork(SEEKER_MATERIALIZATION); new_dude->beamin.InitializeAnim (&beam_in_part1, STANDARD_FRAME_RATE); } if (breed == YELLOW_SEEKER) { if (yellow_piece_cel == NULL) LoadArtwork(YELLOW_SEEKER); new_dude->stumbling.InitializeAnim (&yellow_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&yellow_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&yellow_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&yellow_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&yellow_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&yellow_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&yellow_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&yellow_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&yellow_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = FALSE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, YELLOW_SEEKER, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); } if (breed == LTBLUE_SEEKER) { if (ltblue_piece_cel == NULL) LoadArtwork(LTBLUE_SEEKER); new_dude->stumbling.InitializeAnim (<blue_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (<blue_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (<blue_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (<blue_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (<blue_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (<blue_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (<blue_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (<blue_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (<blue_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, LTBLUE_SEEKER, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); } if (breed == PINK_SEEKER) { if (pink_piece_cel == NULL) LoadArtwork(PINK_SEEKER); new_dude->stumbling.InitializeAnim (&pink_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&pink_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&pink_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&pink_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&pink_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&pink_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&pink_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&pink_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&pink_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = FALSE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, PINK_SEEKER, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); } if (breed == LIME_SEEKER) { if (lime_piece_cel == NULL) LoadArtwork(LIME_SEEKER); new_dude->stumbling.InitializeAnim (&lime_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&lime_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&lime_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&lime_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&lime_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&lime_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&lime_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&lime_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&lime_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, LIME_SEEKER, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->special_anim.InitializeAnim (&lime_still, STANDARD_FRAME_RATE); } if (breed == DORMANT_CHAMELEON) { /* special notes for Chameleons: Because we are substituting these guy in */ /* in places where green guys already exist, we will be using the row and */ /* column values differently for these guys that for normal seekers. Here, */ /* they will specify the actual X and Y coordinates at which the seeker */ /* will be placed. Also, the initial call to SendHome will not be made. */ if (cham_wakeup_anim.anim_pointer == NULL) LoadArtwork(DORMANT_CHAMELEON); new_dude->stumbling.InitializeAnim (&lime_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&lime_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&lime_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&lime_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&lime_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&lime_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&lime_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&lime_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&lime_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = TRUE; new_dude->special_anim.InitializeAnim (&cham_wakeup_anim, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); new_dude->special_anim.current_frame_ccb->ccb_XPos = row; new_dude->special_anim.current_frame_ccb->ccb_YPos = column; population.AddToList(new_dude->special_anim.current_frame_ccb, DORMANT_CHAMELEON, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->solids_entry = population.FindPointerIntoList (new_dude->special_anim.current_frame_ccb); } if (breed == DORMANT_BUMMER) { if (bummer_wakeup_anim.anim_pointer == NULL) LoadArtwork(DORMANT_BUMMER); new_dude->stumbling.InitializeAnim (<blue_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (<blue_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (<blue_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (<blue_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (<blue_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (<blue_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (<blue_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (<blue_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (<blue_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = TRUE; new_dude->special_anim.InitializeAnim (&bummer_wakeup_anim, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); new_dude->special_anim.current_frame_ccb->ccb_XPos = row; new_dude->special_anim.current_frame_ccb->ccb_YPos = column; population.AddToList(new_dude->special_anim.current_frame_ccb, DORMANT_BUMMER, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->solids_entry = population.FindPointerIntoList (new_dude->special_anim.current_frame_ccb); } if (breed == DORMANT_REDCOAT) { if (redcoat_wakeup_anim.anim_pointer == NULL) LoadArtwork(DORMANT_REDCOAT); new_dude->stumbling.InitializeAnim (&lurker_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&lurker_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&lurker_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&lurker_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&lurker_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&lurker_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&lurker_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&lurker_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&lurker_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = TRUE; new_dude->special_anim.InitializeAnim (&redcoat_wakeup_anim, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); new_dude->special_anim.current_frame_ccb->ccb_XPos = row; new_dude->special_anim.current_frame_ccb->ccb_YPos = column; population.AddToList(new_dude->special_anim.current_frame_ccb, DORMANT_REDCOAT, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->solids_entry = population.FindPointerIntoList (new_dude->special_anim.current_frame_ccb); } if (breed == ZOMBIE) { if (zombie_birth.anim_pointer == NULL) LoadArtwork(ZOMBIE); new_dude->stumbling.InitializeAnim (&zombie1pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&zombie1_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim(&zombie1_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim(&zombie1_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&zombie1_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&zombie1_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim(&zombie1_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim(&zombie1_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&zombie1_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = TRUE; new_dude->special_anim.InitializeAnim (&zombie_birth, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); population.AddToList(new_dude->walk_anim[0].current_frame_ccb, ZOMBIE, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); /* if no home tile was assigned, pick one at random from the available swamp tiles */ while (new_dude->home_offset == RANDOM) { new_dude->home_offset = NO_DIRECTION; i = pavement.SelectSwampAtRandom(new_dude->home_row,new_dude->home_column); j = 0; traversal_list = seeker_list; /* Now go through the seeker list and make sure no one else has this tile */ while (traversal_list != (dude *) NULL) { if (traversal_list->breed == ZOMBIE) { if ((traversal_list->home_offset == NO_DIRECTION) && (traversal_list->home_row == new_dude->home_row) && (traversal_list->home_column == new_dude->home_column)) new_dude->home_offset = RANDOM; j++; } traversal_list = traversal_list->next; } /* however, if there are more Zombies than swamp tiles, it's ok to double up */ if ((new_dude->home_offset == RANDOM) && (i <= j)) new_dude->home_offset = NO_DIRECTION; } } if (breed == LURKER) { if (lurker_walk_e.anim_pointer == NULL) LoadArtwork(LURKER); new_dude->stumbling.InitializeAnim (&lurker_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&lurker_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&lurker_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&lurker_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&lurker_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&lurker_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&lurker_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&lurker_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&lurker_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, LURKER, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->special_anim.InitializeAnim (&lurker_wait, STANDARD_FRAME_RATE); } if (breed == MEANY) { if (meany_walk_e_w_n_s.anim_pointer == NULL) LoadArtwork(MEANY); new_dude->stumbling.InitializeAnim (&meany_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&meany_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim(&meany_walk_ne_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim(&meany_walk_se_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&meany_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&meany_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim(&meany_walk_se_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim(&meany_walk_ne_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&meany_walk_e_w_n_s, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, MEANY, PYRAMID_COL_DETECT_X + 2, PYRAMID_COL_DETECT_Y + 2); new_dude->special_anim.InitializeAnim (&meany_stasis, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); new_dude->special = -1; } if (breed == NASTY) { if (nasty_walk_e_w_n_s.anim_pointer == NULL) LoadArtwork(NASTY); new_dude->stumbling.InitializeAnim (&nasty_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&nasty_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim(&nasty_walk_ne_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim(&nasty_walk_se_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&nasty_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&nasty_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim(&nasty_walk_se_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim(&nasty_walk_ne_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&nasty_walk_e_w_n_s, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, NASTY, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->special_anim.InitializeAnim (&nasty_stasis, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); } if (breed == GRUMPY) { if (grumpy_walk_e_w_n_s.anim_pointer == NULL) LoadArtwork(GRUMPY); new_dude->stumbling.InitializeAnim (&grumpy_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&grumpy_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim(&grumpy_walk_ne_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim(&grumpy_walk_se_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&grumpy_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&grumpy_walk_e_w_n_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim(&grumpy_walk_se_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim(&grumpy_walk_ne_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&grumpy_walk_e_w_n_s, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = FALSE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, GRUMPY, PYRAMID_COL_DETECT_X - 1, PYRAMID_COL_DETECT_Y); } if (breed == JUGGERNAUT) { if (jugger_pit_death.anim_pointer == NULL) LoadArtwork(JUGGERNAUT); new_dude->stumbling.InitializeAnim (&jugger_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&jugger_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&jugger_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&jugger_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&jugger_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&jugger_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&jugger_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&jugger_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&jugger_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = FALSE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, JUGGERNAUT, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); } if (breed == PSYCHO) { if (psycho_pit_death.anim_pointer == NULL) LoadArtwork(PSYCHO); new_dude->stumbling.InitializeAnim (&psycho_pit_death, STANDARD_FRAME_RATE); new_dude->walk_anim[EAST].InitializeAnim (&psycho_walk_e, STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHEAST].InitializeAnim (&psycho_walk_ne,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTHWEST].InitializeAnim (&psycho_walk_nw,STANDARD_FRAME_RATE); new_dude->walk_anim[NORTH].InitializeAnim (&psycho_walk_n, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTH].InitializeAnim (&psycho_walk_s, STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHEAST].InitializeAnim (&psycho_walk_se,STANDARD_FRAME_RATE); new_dude->walk_anim[SOUTHWEST].InitializeAnim (&psycho_walk_sw,STANDARD_FRAME_RATE); new_dude->walk_anim[WEST].InitializeAnim (&psycho_walk_w, STANDARD_FRAME_RATE); for (i = 0; i < 8; i++) new_dude->walk_anim[i].Restart(); new_dude->avoid_hazards = TRUE; new_dude->avoid_obstacles = TRUE; population.AddToList(new_dude->walk_anim[0].current_frame_ccb, PSYCHO, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); new_dude->special_anim.InitializeAnim (&psycho_unmoving, STANDARD_FRAME_RATE); new_dude->special_anim.Restart(); new_dude->special = FALSE; } new_dude->next = seeker_list; seeker_list = new_dude; if ((breed != DORMANT_CHAMELEON) && (breed != DORMANT_REDCOAT) && (breed != DORMANT_BUMMER)) { if ((new_dude->home_offset == NO_DIRECTION) && (breed != ZOMBIE)) { if ((level_lookup_table[row][column] != FA_TILE) && (level_lookup_table[row][column] != FB_TILE)) { printf("HEY!!!! You put a seeker on a tile that can't generate them!\n"); new_dude->home_offset = NORTH; } } new_dude->solids_entry = population.FindPointerIntoList (new_dude->walk_anim[0].current_frame_ccb); if (homeward_bound) SendHome(new_dude); } SetSeekerSpeeds(new_dude); return (new_dude);}/***************************** seeker::EliminateSeeker ********************************* Most of the time, when a seeker is destroyed in game terms, it isn't really destroyed. It is shown being destroyed, but it is instantly reincarnated back at its home tile. However, in the final stages of the game, when all non-seeker pyramids have been destroyed, then the seekers can be truly eliminated, one by one. This function is used at that point, to delete seekers from the list and deallocate the memory used to keep track of them.*****************************************************************************************/void seeker::EliminateSeeker (register dude *target) { dude *traversal_ptr; int32 i; /* if object is at head of list, adjust master list pointer */ if (target == seeker_list) seeker_list = target->next; else { /* look through the list until we find the target, then cut it out of the list */ traversal_ptr = seeker_list; while (traversal_ptr->next != target) traversal_ptr = traversal_ptr->next; traversal_ptr->next = traversal_ptr->next->next; } /* now free up the memory used by the record */ for (i = 0; i < 8; i++) target->walk_anim[i].ShutdownForRestart(); target->stumbling.ShutdownForRestart(); target->special_anim.ShutdownForRestart(); delete(target);}/******************************* seeker::SendHome ************************************* Most of the time, when a seeker is destroyed in game terms, it isn't really destroyed. It is shown being destroyed, but it is instantly reincarnated back at its home tile. This function is used to move the seeker back to its home location, or at least as near to that home location as possible. Each seeker's record contains a set of 3 values which determine its home. The first 2 are the row and column values for a tile somewhere on the landscape; the third is an offset direction from that tile. Most seekers are meant to appear as if they simply emerge from the wasteland, so most home values are set to tiles on the edge of the landscape, with the offset directions forcing the seeker out into the wasteland. However, if that patch of wasteland is actually visible on screen when a seeker is returned to that spot, then the seeker will visually pop into existence in a way that we do not wish to allow. Thus, if the seeker's home tile is visible, then the seeker is instead reincarnated a screen's distance away from the home tile, in the direction of the offset. There are 2 versions of the SendHome function. The first (this one) conducts all of the real business of sending a seeker home, based on a pointer into the seeker list. The second version takes as input a pointer to the seeker's solid object record, uses it to find the right entry on the seeker list, and then calls this function.*****************************************************************************************/void seeker::SendHome(register dude *target){ CCB *temp_ccb; int32 i,j; int32 row, column, offset; target->move_status = NORMAL_MOVEMENT; target->current_row = -1; target->current_column = -1; target->walk_anim[target->direction].Restart(); /* do cleanup for cases where the seeker got shot while starting to fall into a pit. */ if (target->health == STUMBLING) { target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->stumbling.Restart(); } /* randomize the frame number that we're on (unless we're a NASTY or a GRUMPY). */ if ((target->breed != NASTY) && (target->breed != GRUMPY)) { j = RandomNumber(1,20); for (i = 0; i <= j; i++) target->walk_anim[target->direction].AdvanceFrame(); } /* However, if the seeker is a NASTY we need to make a special point of cueing */ /* to the frame in which the pyramid is normal, so that it kicks off properly */ /* after splitting. */ if (target->breed == NASTY) { for (i = 0; i <= 6; i++) target->walk_anim[target->direction].AdvanceFrame(); } /* if all static pyramids have been destroyed, then seekers get eliminated */ if ((g_total_pyramids == 0) && (target->breed != NASTY) && (target->breed != GRUMPY)) { population.EliminateObject(target->solids_entry); EliminateSeeker(target); return; } /* Also, some seekers (i.e. chameleons) never regenerate at all. */ if ((target->breed == DORMANT_CHAMELEON) || (target->breed == WAKING_CHAMELEON) || (target->breed == ACTIVE_CHAMELEON) || (target->breed == DORMANT_REDCOAT) || (target->breed == WAKING_REDCOAT) || (target->breed == ACTIVE_REDCOAT) || (target->breed == DORMANT_BUMMER) || (target->breed == WAKING_BUMMER) || (target->breed == ACTIVE_BUMMER)) { if ((target->breed != ACTIVE_CHAMELEON) && (target->breed != ACTIVE_REDCOAT) && (target->breed != ACTIVE_BUMMER)) g_total_pyramids--; population.EliminateObject(target->solids_entry); EliminateSeeker(target); return; } if ((target->breed == NASTY) && (target->health != NOT_DEAD)) { grumpy_death_toll += 2; row = target->home_row; column = target->home_column; offset = target->home_offset; population.EliminateObject(target->solids_entry); EliminateSeeker(target); if ((grumpy_death_toll >= 4) && (g_total_pyramids != 0)) { grumpy_death_toll -= 4; CreateSeeker(MEANY, row, column, offset, TRUE); } return; } if ((target->breed == GRUMPY) && (target->health != NOT_DEAD)) { grumpy_death_toll += 1; row = target->home_row; column = target->home_column; offset = target->home_offset; population.EliminateObject(target->solids_entry); EliminateSeeker(target); if ((grumpy_death_toll >= 4) && (g_total_pyramids != 0)) { grumpy_death_toll -= 4; CreateSeeker(MEANY, row, column, offset, TRUE); } return; } if (target->breed == LURKER) { target->special = LURKER_AWAKE_PHASE - 2; target->special_anim.Restart(); target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; } /* if we haven't returned, then we regenerate the seeker */ /* do special handling for Zombies. */ if (target->breed == ZOMBIE) { target->special = (-1) * (RandomNumber(15,30)); target->health = NOT_DEAD; target->blocker = (solid_object *) NULL; /* switch back to the zombie 1 walking artwork */ target->walk_anim[EAST].ChangeArt (&zombie1_walk_e); target->walk_anim[NORTHEAST].ChangeArt (&zombie1_walk_ne); target->walk_anim[NORTHWEST].ChangeArt (&zombie1_walk_nw); target->walk_anim[NORTH].ChangeArt (&zombie1_walk_n); target->walk_anim[SOUTH].ChangeArt (&zombie1_walk_s); target->walk_anim[SOUTHEAST].ChangeArt (&zombie1_walk_se); target->walk_anim[SOUTHWEST].ChangeArt (&zombie1_walk_sw); target->walk_anim[WEST].ChangeArt (&zombie1_walk_w); /* hide the walk anims way off screen: */ for (i = 0; i < 8; i++) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = 0xFFF0000; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = 0xFFF0000; } population.FixPositionOnList(target->solids_entry); target->stumbling.ChangeArt(&zombie1pit_death); if (target->home_offset == NO_DIRECTION) { target->current_row = target->home_row; target->current_column = target->home_column; return; } else target->special = 1; } /* Now handle all normal seeker types */ target->health = NOT_DEAD; target->blocker = (solid_object *) NULL; temp_ccb = pavement.FetchTileCCB(target->home_row,target->home_column); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = temp_ccb->ccb_XPos; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = temp_ccb->ccb_YPos; if (target->home_offset == NORTH) { target->walk_anim[target->direction].current_frame_ccb->ccb_YPos -= (TILE_HEIGHT << 16); while ((ObjectVisible(target->walk_anim[target->direction].current_frame_ccb)) || (Obstructed(target,FALSE))) target->walk_anim[target->direction].current_frame_ccb->ccb_YPos -= ((SCREEN_HEIGHT / 4) << 16); } else if (target->home_offset == SOUTH) { target->walk_anim[target->direction].current_frame_ccb->ccb_YPos += (TILE_HEIGHT << 16); while ((ObjectVisible(target->walk_anim[target->direction].current_frame_ccb)) || (Obstructed(target,FALSE))) target->walk_anim[target->direction].current_frame_ccb->ccb_YPos += ((SCREEN_HEIGHT / 4) << 16); } else if (target->home_offset == WEST) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos -= (TILE_WIDTH << 16); while ((ObjectVisible(target->walk_anim[target->direction].current_frame_ccb)) || (Obstructed(target,FALSE))) target->walk_anim[target->direction].current_frame_ccb->ccb_XPos -= ((SCREEN_WIDTH / 4) << 16); } else if (target->home_offset == EAST) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos += (TILE_WIDTH << 16); while ((ObjectVisible(target->walk_anim[target->direction].current_frame_ccb)) || (Obstructed(target,FALSE))) target->walk_anim[target->direction].current_frame_ccb->ccb_XPos += ((SCREEN_WIDTH / 4) << 16); } else if ((target->breed != NASTY) && (target->breed != GRUMPY)) { /* seeker generator tile handling goes here. */ target->health = MATERIALIZING_1; /* hide the walk anims way off screen: */ for (i = 0; i < 8; i++) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = 0xFFF0000; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = 0xFFF0000; } /* set solids pointer to look at beam in anim, and hide it way off screen too */ target->solids_entry->cel = target->beamin.current_frame_ccb; target->beamin.current_frame_ccb->ccb_XPos = 0xFFF0000; target->beamin.current_frame_ccb->ccb_YPos = 0xFFF0000; target->beamin.Restart(); target->last_hazard = temp_ccb; } population.FixPositionOnList(target->solids_entry);}/******************************* seeker::SendHome ************************************* Most of the time, when a seeker is destroyed in game terms, it isn't really destroyed. It is shown being destroyed, but it is instantly reincarnated back at its home tile. This function is used to move the seeker back to its home location. There are 2 versions of the SendHome function. The first version conducts all of the real business of sending a seeker home, based on a pointer into the seeker list. The second (this one) takes as input a pointer to the seeker's solid object record, uses it to find the right entry on the seeker list, and then calls the other function.*****************************************************************************************/void seeker::SendHome(solid_object *target){ dude *traversal_ptr; traversal_ptr = seeker_list; while (traversal_ptr != (dude *) NULL) { if (traversal_ptr->solids_entry == target) { SendHome(traversal_ptr); return; } traversal_ptr = traversal_ptr->next; } printf("Danger Will Robinson! Failure in attempt to send home a seeker!\n");}/**************************** seeker::GetSeekerHealth ********************************** Given a seeker's solid object pointer, this function pulls up the full record for thatseeker and returns its health value.*****************************************************************************************/int32 seeker::GetSeekerHealth(solid_object *target, int32 &row, int32 &column){ dude *traversal_ptr; traversal_ptr = seeker_list; while (traversal_ptr != (dude *) NULL) { if (traversal_ptr->solids_entry == target) { row = traversal_ptr->current_row; column = traversal_ptr->current_column; return(traversal_ptr->health); } traversal_ptr = traversal_ptr->next; } printf("Dang. Couldn't find the seeker you wanted to see the health records on.\n"); return(DEAD);}/**************************** seeker::DetermineDirection ******************************* This function figures out which direction a seeker is now moving in, based on whereit was and where it is now.*****************************************************************************************/int32 seeker::DetermineDirection (register dude *target, int32 old_x, int32 old_y){ int32 new_direction; new_direction = NO_DIRECTION; if (old_x > target->walk_anim[target->direction].current_frame_ccb->ccb_XPos) new_direction = WEST; if (old_x < target->walk_anim[target->direction].current_frame_ccb->ccb_XPos) new_direction = EAST; if (old_y > target->walk_anim[target->direction].current_frame_ccb->ccb_YPos) { if (new_direction == NO_DIRECTION) new_direction = NORTH; if (new_direction == WEST) new_direction = NORTHWEST; if (new_direction == EAST) new_direction = NORTHEAST; } if (old_y < target->walk_anim[target->direction].current_frame_ccb->ccb_YPos) { if (new_direction == NO_DIRECTION) new_direction = SOUTH; if (new_direction == WEST) new_direction = SOUTHWEST; if (new_direction == EAST) new_direction = SOUTHEAST; } if (new_direction == NO_DIRECTION) return(target->direction); return(new_direction);}/**************************** seeker::ChangeDirection ********************************** When a seeker's direction changes from one compass point to a different compass point,it becomes necessary to change the animation being displayed from the one for the oldcompass point to the one for the new compass point. This function first sets the newanimation's location and frame number to be the same as the old animation's location andframe number and then switches the pointer in the solids database so that the newanimation will be shown.*****************************************************************************************/void seeker::ChangeDirection (register dude *target, int32 new_direction){ target->walk_anim[new_direction].current_frame_ccb->ccb_XPos = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; target->walk_anim[new_direction].current_frame_ccb->ccb_YPos = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; target->walk_anim[new_direction].current_frame_number = target->walk_anim[target->direction].current_frame_number; target->solids_entry->cel = target->walk_anim[new_direction].current_frame_ccb; target->direction = new_direction;}/**************************** seeker::AnimateSeekers ********************************** This function drives the movement of all of the seekers on the level. It works through the linked list of seekers and in each case attempts to move the seeker, as per the ability of the type of seeker in question. Depending on the intelligence settings of the seeker, this function will call the appropriate movement handling function. If the move was successful, i.e. the seeker wasn't obstructed or otherwise prevented from moving, then this function will advance the walking animation for the seeker and make sure that the seeker is still properly sorted on the all-encompassing solids list. Lastly, it will check the ground it's walking on to make sure the seeker didn't step in anything. If it did, then this function will take appropriate measures. Seekers who stepped in something on previous pass through this routine but who haven't actually died yet require special attention. No attempt will be made to move seekers in this type of situation; instead, appropriate calls will be made to complete the process that was kicked off when they first stepped in whatever it was that they stepped in.*****************************************************************************************/void seeker::AnimateSeekers(int32 x_change, int32 y_change){ register dude *target; bool moved; int32 old_x,old_y; int32 new_direction; dude *next_target; moved = FALSE; target = seeker_list; while (target != (dude *) NULL) { //DumpMovementStatus(target); next_target = target->next; old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; /* If we have a pointer to an object that was blocking us, check to make sure */ /* said object still exists. If it doesn't, discard our pointer to that object. */ if ((target->blocker != (solid_object *) NULL) && (target->blocker->cel == (CCB *) NULL)) target->blocker = (solid_object *) NULL; if (target->health == NOT_DEAD) { moved = FALSE; target->previous_x += x_change; target->previous_y += y_change; if ((target->breed == DORMANT_CHAMELEON) || (target->breed == WAKING_CHAMELEON) || (target->breed == DORMANT_REDCOAT) || (target->breed == WAKING_REDCOAT) || (target->breed == DORMANT_BUMMER) || (target->breed == WAKING_BUMMER)) MaintainChameleon(target); else if ((target->breed == ZOMBIE) && (target->special < 1)) ReviveZombie(target); else if (((target->breed == LURKER) || (target->breed == ACTIVE_REDCOAT)) && (target->special < 0)) { target->stranded_counter = 0; target->special++; target->special_anim.AdvanceFrame(); if ((target->special == 0) && (!(target->special_anim.AnimCued()))) target->special--; if (target->special == 0) { target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->special_anim.current_frame_ccb->ccb_XPos; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->special_anim.current_frame_ccb->ccb_YPos; } } else { /* some seekers need to be stopped for a frame or 2 to make their movement */ /* animations look right. */ if ((target->breed == YELLOW_SEEKER) && (target->walk_anim[target->direction].AnimComplete())) moved = TRUE; if ((target->breed == MEANY) && ((target->walk_anim[target->direction].AnimComplete()) || (target->walk_anim[target->direction].AnimCued()))) moved = TRUE; if ((target->breed == NASTY) && (target->walk_anim[target->direction].AnimComplete())) moved = TRUE; /* now, if we haven't halted the seeker, move it according to its smarts. */ if (!(moved)) { if ((!(target->avoid_hazards)) && (!(target->avoid_obstacles))) moved = StupidMovement(target); if ((!(target->avoid_hazards)) && (target->avoid_obstacles)) moved = RiskyMovement(target); if (target->avoid_hazards) { if (target->stranded_counter > 4) { target->blocker = (solid_object *) NULL; moved = StupidMovement(target); target->blocker = (solid_object *) NULL; target->stranded_counter = 0; } else moved = BrainyMovement(target); } if (moved) DealWithInvisibleFence(target,old_x,old_y); } if (moved) { target->immobile_counter = 0; new_direction = DetermineDirection(target,old_x,old_y); if (new_direction != target->direction) ChangeDirection(target, new_direction); target->walk_anim[target->direction].AdvanceFrame(); population.FixPositionOnList(target->solids_entry); if ((target->breed == LURKER) || (target->breed == ACTIVE_REDCOAT)) { target->special++; if ((target->special >= LURKER_AWAKE_PHASE) && (target->walk_anim[target->direction].AnimCued())) { target->special = (-1) * LURKER_SLEEP_PHASE; target->solids_entry->cel = target->special_anim.current_frame_ccb; target->special_anim.current_frame_ccb->ccb_XPos = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; target->special_anim.current_frame_ccb->ccb_YPos = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; } } } else { target->immobile_counter++; /* Even though we aren't moving, keeping playing animation until */ /* re-cued so that it doesn't stop on a frame that looks dumb. On the */ /* other hand, some seekers never really stop, so keep animating them. */ switch (target->breed) { case PSYCHO: case LURKER: case ACTIVE_REDCOAT: case LIME_SEEKER: case ACTIVE_CHAMELEON: target->walk_anim[target->direction].AdvanceFrame(); break; case MEANY: if (!(target->walk_anim[target->direction].AnimOnGivenFrame(9))) target->walk_anim[target->direction].AdvanceFrame(); break; case NASTY: if (!(target->walk_anim[target->direction].AnimOnGivenFrame(7))) target->walk_anim[target->direction].AdvanceFrame(); break;// case JUGGERNAUT:// if (!(target->walk_anim[target->direction].AnimOnGivenFrame(18)))// target->walk_anim[target->direction].AdvanceFrame();// break; default: if (!(target->walk_anim[target->direction].AnimCued())) target->walk_anim[target->direction].AdvanceFrame(); break; } } if ((moved) || (target->avoid_hazards == TRUE)) { DealWithSwamp(target); if (pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, ((target->avoid_hazards) && (target->avoid_obstacles) && (target->breed != MEANY)))) { CommenceHazardDeath(target); if ((target->health == NOT_DEAD) && (!moved)) RunAway(target); } } } } switch (target->health) { case NOT_DEAD: if ((old_x == target->walk_anim[target->direction]. current_frame_ccb->ccb_XPos) && (old_y == target->walk_anim[target->direction]. current_frame_ccb->ccb_YPos)) target->stranded_counter++; else target->stranded_counter = 0; break; case STUMBLING: PullIntoHazard(target); break; case CONSUMED_BY_LAVA: target->walk_anim[target->direction].AdvanceFrame(); PullIntoHazard(target); break; case SPLITTING: MaintainSplitter(target); CheckForCorruptedGrumpies(); break; case SPLITTING_STASIS: NurgeSplitter(target); CheckForCorruptedGrumpies(); break; case MATERIALIZING_1: ScottyEnergize(target); break; case MATERIALIZING_2: ScottyEnergize(target); break; case MATERIALIZING_3: ScottyEnergize(target); break; case DEAD: population.EliminateObject(target->solids_entry); EliminateSeeker(target); break; default: printf("hey"); } target = next_target; }}/************************* seeker::DealWithInvisibleFence ****************************** This function implements an invisible fence that keeps all types of seekers fromjourneying too far into the wasteland, the purpose of which is to eliminate theeffectivness of the cheeseball strategy of getting all the seekers to follow you as yougo way out into the wasteland, and then racing back to destroy pyramids unharrassed.With the invisible fence in place, seekers will only go a certain distance out into thewasteland, and then they'll stop and wait for you to come back, tracking you along theedge of the fence as you move.*****************************************************************************************/void seeker::DealWithInvisibleFence (dude *target, int32 old_x, int32 old_y){ int32 which_way; CCB *dude_cel; int32 new_x; int32 new_y; /* first, make sure that the dudemeyer is really outside the fence. If it isn't, but */ /* the seeker has someone gotten beyond the fence (this can happen, for example, */ /* with orange meanies when they get shot at the edge of the fence), then we return */ /* immediately so that the seeker can be back inside the fence. */ which_way = AreWeLost(icebreaker.dudemeyer_cel->ccb_XPos, icebreaker.dudemeyer_cel->ccb_YPos, pavement.center_tile->ccb_XPos, pavement.center_tile->ccb_YPos, 2); if (which_way == NO_DIRECTION) return; /* now check to see if our new move has placed us outside of the fence. If it has, */ /* then we go back to where we were and then try moving along the edge of the fence. */ dude_cel = target->walk_anim[target->direction].current_frame_ccb; which_way = AreWeLost(dude_cel->ccb_XPos, dude_cel->ccb_YPos, pavement.center_tile->ccb_XPos,pavement.center_tile->ccb_YPos,2); if (which_way != NO_DIRECTION) { target->stranded_counter = 0; dude_cel->ccb_XPos = old_x; dude_cel->ccb_YPos = old_y; // figure out our desired move, then figure out which part of it is allowable. HeadForTheDudemeyer(dude_cel, target->horz_speed, target->vert_speed); new_x = dude_cel->ccb_XPos; new_y = dude_cel->ccb_YPos; dude_cel->ccb_XPos = old_x; dude_cel->ccb_YPos = old_y; /* audtion the x axis component */ dude_cel->ccb_XPos = new_x; which_way = AreWeLost(dude_cel->ccb_XPos, dude_cel->ccb_YPos, pavement.center_tile->ccb_XPos, pavement.center_tile->ccb_YPos,2); if (which_way != NO_DIRECTION) new_x = old_x; dude_cel->ccb_XPos = old_x; /* audtion the y axis component */ dude_cel->ccb_YPos = new_y; which_way = AreWeLost(dude_cel->ccb_XPos, dude_cel->ccb_YPos, pavement.center_tile->ccb_XPos, pavement.center_tile->ccb_YPos,2); if (which_way != NO_DIRECTION) new_y = old_y; dude_cel->ccb_YPos = old_y; /* now use whatever is usable */ dude_cel->ccb_XPos = new_x; dude_cel->ccb_YPos = new_y; if (!(Obstructed(target,FALSE))) { /* if we've moved once, set the stale detour flags to the current detour flags */ if (target->obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = target->obstacle_detour_axis; target->obstacle_detour_axis = NO_AXIS; } /* if we've moved successfully twice in a row, clear out the stale detour flags */ else if (target->old_obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = NO_AXIS; } which_way = AreWeLost(dude_cel->ccb_XPos, dude_cel->ccb_YPos, pavement.center_tile->ccb_XPos, pavement.center_tile->ccb_YPos,2); if (which_way != NO_DIRECTION) { dude_cel->ccb_XPos = old_x; dude_cel->ccb_YPos = old_y; } return; } AvoidObstruction(target,old_x,old_y,RandomNumber(0,target->horz_speed), RandomNumber(0,target->vert_speed)); which_way = AreWeLost(dude_cel->ccb_XPos, dude_cel->ccb_YPos, pavement.center_tile->ccb_XPos, pavement.center_tile->ccb_YPos,2); if (which_way != NO_DIRECTION) { dude_cel->ccb_XPos = old_x; dude_cel->ccb_YPos = old_y; } }}/****************************** seeker::Obstructed ************************************ Although this is a boolean function, there are really 3 cases that can result from a call to this function. 1.) There is nothing in the path of the seeker, in which case we return FALSE. 2.) There is an object in the path of the seeker that the seeker can destroy simply by touching it, in which case we carry out the destruction of that object and then, since it is no longer an obstruction, we return FALSE. Note that this includes destroying the dudemeyer itself! 3.) There is an object that the seeker cannot destroy by ramming but which is also not harmful to seekers, in which case it is blocked and we return TRUE. In this case, we also make a note of which object it is that is blocking our way, so that on future calls to this function, we can simply check to see if that object is still blocking our way instead of doing a full collision check just to find out this information.*****************************************************************************************/bool seeker::Obstructed(register dude *target, bool ignore_rocks){ /* if it is not true that something blocked us previously and is still blocking us, */ /* then we check against everything to see if something is blocking us anew. */ if ( ! ( (target->blocker != (solid_object *) NULL) && (population.CompareForCollisions(target->solids_entry,target->blocker)) ) ) { target->blocker = population.DetectCollision(target->solids_entry, ignore_rocks); } /* if blocker is NULL, then we're free to go! */ if (target->blocker == (solid_object *) NULL) return(FALSE); /* otherwise, check the various types of objects and see if there's anything we can */ /* get rid of on our own. */ if (target->blocker->object_type == GREEN_PYRAMID) { PlaySoundEffect(PULVERIZE_SOUND); morgue.CreateDeathScene (&population.green_death, STANDARD_FRAME_RATE, target->blocker->cel->ccb_XPos, target->blocker->cel->ccb_YPos, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y,0); population.EliminateObject(target->blocker); g_total_pyramids--; target->blocker = (solid_object *) NULL; return(FALSE); } if ((target->blocker->object_type == DUDEMEYER) && (g_dead == NOT_DEAD)) { if ((target->health == MATERIALIZING_1) || (target->health == MATERIALIZING_2)) return(TRUE); PlaySoundEffect(DEATH_SOUND); g_dead = CAUGHT_BY_SEEKER; target->blocker = (solid_object *) NULL; return(FALSE); } target->stranded_counter = 0; return(TRUE);}/***************************** seeker::StupidMovement ********************************** This function handles the movement abilities for the stupidest of the seekers. This seeker always attempts to move in the most direct path towards the dudemeyer (i.e. towards the center of the screen). If anything gets in its way, then the seeker will stop and wait until the object in it's path disappears somehow, or until the objective's location has moved enough that the most direct path to the objective is no longer obstructed.*****************************************************************************************/bool seeker::StupidMovement(register dude *target){ int32 old_x,old_y; old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; target->last_hazard = (CCB *) NULL; /* if we were blocked before, just try choking up on what's blocking us */ if (target->blocker != (solid_object *) NULL) HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, (1 << 16),(1 << 16)); /* but if were weren't blocked, move forward at full throttle */ else HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, target->horz_speed, target->vert_speed); if (Obstructed(target,FALSE)) { /* It often happens that a pair of stupid seekers will get stuck on each other, */ /* and it looks dumb when it happens. Thus, we give a tiny bit of smarts to these */ /* guys: They can avoid other seekers. */ if ((target->blocker->object_type >= FIRST_SEEKER) && (target->blocker->object_type <= LAST_SEEKER)) return (AvoidObstruction(target,old_x,old_y, RandomNumber(0,target->horz_speed), RandomNumber(0,target->vert_speed))); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; return(FALSE); } /* having provided these guys with a small bit of intelligence, we must also manage */ /* this intelligence. if we've moved once, set the stale detour flags to the current */ /* detour flags */ if (target->obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = target->obstacle_detour_axis; target->obstacle_detour_axis = NO_AXIS; } /* if we've moved successfully twice in a row, clear out the stale detour flags */ else if (target->old_obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = NO_AXIS; } return(TRUE);}/**************************** seeker::PlanObstacleDetour ****************************** This function is used by AvoidObstruction to determine on which axis to take a detourwhen trying to get around an obstacle, and then, in which direction to go.*****************************************************************************************/void seeker::PlanObstacleDetour (register dude *target, int32 x, int32 y){ x = (x >> 16) + HALF_TILE_WIDTH; y = (y >> 16) + HALF_TILE_HEIGHT; if (target->move_status == PRIME_DETOUR) { if (target->hazard_detour_axis == X_AXIS) target->obstacle_detour_axis = Y_AXIS; else target->obstacle_detour_axis = X_AXIS; target->obstacle_detour_direction = target->alternate_hazard_direction; } if (target->move_status == HOUDINI_MODE) { target->obstacle_detour_axis = target->hazard_detour_axis; if (target->alternate_hazard_direction == PLUS_DIRECTION) target->obstacle_detour_direction = MINUS_DIRECTION; else target->obstacle_detour_direction = PLUS_DIRECTION; } if (target->move_status == ALT_DETOUR) { target->obstacle_detour_axis = target->hazard_detour_axis; target->obstacle_detour_direction = target->hazard_detour_direction; } if (target->move_status == NORMAL_MOVEMENT) { if (((ABS(y - SCREEN_CENTER_Y))) >= ((ABS(x - SCREEN_CENTER_X)))) { target->obstacle_detour_axis = X_AXIS; if (x > SCREEN_CENTER_X) target->obstacle_detour_direction = MINUS_DIRECTION; if (x < SCREEN_CENTER_X) target->obstacle_detour_direction = PLUS_DIRECTION; if (x == SCREEN_CENTER_X) { if (FIND_CENTER_X(target->blocker->cel) > SCREEN_CENTER_X) target->obstacle_detour_direction = MINUS_DIRECTION; if (FIND_CENTER_X(target->blocker->cel) < SCREEN_CENTER_X) target->obstacle_detour_direction = PLUS_DIRECTION; if (FIND_CENTER_X(target->blocker->cel) == SCREEN_CENTER_X) target->obstacle_detour_direction = RandomNumber(PLUS_DIRECTION, MINUS_DIRECTION); } } else { target->obstacle_detour_axis = Y_AXIS; if (y > SCREEN_CENTER_Y) target->obstacle_detour_direction = MINUS_DIRECTION; if (y < SCREEN_CENTER_Y) target->obstacle_detour_direction = PLUS_DIRECTION; if (y == SCREEN_CENTER_Y) { if (FIND_CENTER_Y(target->blocker->cel) > SCREEN_CENTER_Y) target->obstacle_detour_direction = MINUS_DIRECTION; if (FIND_CENTER_Y(target->blocker->cel) < SCREEN_CENTER_Y) target->obstacle_detour_direction = PLUS_DIRECTION; if (FIND_CENTER_Y(target->blocker->cel) == SCREEN_CENTER_Y) target->obstacle_detour_direction = RandomNumber(PLUS_DIRECTION, MINUS_DIRECTION); } } }}/***************************** seeker::AvoidObstruction ******************************* Here's how the object avoidance logic works. When a seeker tries to move but is obstructed, it picks an axis to move along and then stays on that axis until the obstruction is cleared. The axis we select for our detour is the axis we are closest to, since we need to move away from the line we are on in order to get out from behind the obstacle. In many cases, once we get clear of an obstacle, we will run into it again almost immediately. This is because once we get out from behind the obstruction, we'll be sitting along side of it, and moving diagonally will make us bash into it again. In this eventuality, we need to move along a second detour route, this time moving along the opposite axis from whichever axis we were moving along earlier. Only when we are fully clear of the obstacle (which we conclude to be the case when we successfully move unobstructedly twice in a row) do we discard our detour plans. Note however, that thisdiscarding of detour plans is done by the routine that calls this routine. This functionsimply attempts to move the seeker according to the detour plans available or newlydetermined.*****************************************************************************************/bool seeker::AvoidObstruction(register dude *target, int32 old_x,int32 old_y, int32 horz_speed, int32 vert_speed){ int32 center_x,center_y; solid_object *old_obstruction; old_obstruction = target->blocker; /* before doing anything, go back to where we were */ target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; center_x = (old_x >> 16) + HALF_TILE_WIDTH; center_y = (old_y >> 16) + HALF_TILE_HEIGHT; if (target->blocker != (solid_object *) NULL) { if ((target->blocker->object_type == DEATH_SCENE) || (target->blocker->object_type == BIRTH_SCENE)) return(FALSE); } if ((target->obstacle_detour_axis == NO_AXIS) && (target->old_obstacle_detour_axis != NO_AXIS)) { if (target->old_obstacle_detour_axis == Y_AXIS) { target->obstacle_detour_axis = X_AXIS; if ((center_x) > SCREEN_CENTER_X) target->obstacle_detour_direction = MINUS_DIRECTION; else target->obstacle_detour_direction = PLUS_DIRECTION; } else { target->obstacle_detour_axis = Y_AXIS; if ((center_y) > SCREEN_CENTER_Y) target->obstacle_detour_direction = MINUS_DIRECTION; else target->obstacle_detour_direction = PLUS_DIRECTION; } } if (target->obstacle_detour_axis == NO_AXIS) PlanObstacleDetour (target, old_x, old_y); /* try moving along detour axis */ FollowHeading (target->walk_anim[target->direction].current_frame_ccb, target->obstacle_detour_axis, target->obstacle_detour_direction, horz_speed, vert_speed); if (Obstructed(target,((target->avoid_hazards) && (target->avoid_obstacles) && (target->breed != MEANY)))) { /* First of all, go back to where we were. */ target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; /* Then, if we haven't moved at all, we must take some sort of action. */ if ((target->previous_x == old_x) && (target->previous_y == old_y)) { target->reversal_counter++; if (target->reversal_counter == 1) { /* on first try, reverse direction only. */ if (target->obstacle_detour_direction == PLUS_DIRECTION) target->obstacle_detour_direction = MINUS_DIRECTION; else target->obstacle_detour_direction = PLUS_DIRECTION; } if (target->reversal_counter == 2) { /* on second try, reverse axis only. */ if (target->obstacle_detour_axis == Y_AXIS) { target->obstacle_detour_axis = X_AXIS; target->old_obstacle_detour_axis = Y_AXIS; } else { target->obstacle_detour_axis = Y_AXIS; target->old_obstacle_detour_axis = X_AXIS; } /* now reset the counter so that we do the first try case again next time. */ target->reversal_counter = 0; } target->blocker = old_obstruction; return(FALSE); } /* if we moved but got blocked again, switch axis and pick new direction. */ if (target->obstacle_detour_axis == Y_AXIS) { target->obstacle_detour_axis = X_AXIS; target->old_obstacle_detour_axis = Y_AXIS; if ((center_x) > SCREEN_CENTER_X) target->obstacle_detour_direction = MINUS_DIRECTION; else target->obstacle_detour_direction = PLUS_DIRECTION; } else { target->obstacle_detour_axis = Y_AXIS; target->old_obstacle_detour_axis = X_AXIS; if ((center_y) > SCREEN_CENTER_Y) target->obstacle_detour_direction = MINUS_DIRECTION; else target->obstacle_detour_direction = PLUS_DIRECTION; } target->reversal_counter = 0; target->previous_x = old_x; target->previous_y = old_y; target->blocker = old_obstruction; return(FALSE); } target->reversal_counter = 0; target->blocker = old_obstruction; return(TRUE);}/***************************** seeker::RiskyMovement ********************************** This function handles the movement abilities for seekers who are smart enough to steer around obstacles but who are too stupid to avoid falling into pits or other such hazards. In other words, they are smarter than seekers who use the StupidMovement function, but they are too willing to take hazardous risks and will thus plunge right into pits without thinking about it.*****************************************************************************************/bool seeker::RiskyMovement(register dude *target){ int32 old_x,old_y; old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; target->last_hazard = (CCB *) NULL; /* try movings towards dudemeyer */ HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, target->horz_speed, target->vert_speed); if (!(Obstructed(target,FALSE))) { /* if we've moved once, set the stale detour flags to the current detour flags */ if (target->obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = target->obstacle_detour_axis; target->obstacle_detour_axis = NO_AXIS; } /* if we've moved successfully twice in a row, clear out the stale detour flags */ else if (target->old_obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = NO_AXIS; } return(TRUE); } else { if ((target->blocker->object_type >= FIRST_SEEKER) && (target->blocker->object_type <= LAST_SEEKER)) return (AvoidObstruction(target,old_x,old_y, RandomNumber(0,target->horz_speed), RandomNumber(0,target->vert_speed))); return (AvoidObstruction(target,old_x,old_y,target->horz_speed, target->vert_speed)); }}/********************************** seeker::RunAway *********************************** This function is used whenever a seeker with hazard avoidance finds itself actuallysitting upon a hazardous tile. If the tile isn't instantly deadly, and the seeker hastime to move off of it, then this function will move the seeker off of the hazardoustile in the most direct possible way.*****************************************************************************************/bool seeker::RunAway (register dude *target){ CCB *dude_ccb; int32 old_x,old_y; bool hazards_ahoy; int32 test_row, test_column; CCB *test_hazard; dude_ccb = target->walk_anim[target->direction].current_frame_ccb; old_x = dude_ccb->ccb_XPos; old_y = dude_ccb->ccb_YPos; /* First, figure out if the tile we're going to move towards is also hazardous. */ if (FIND_CENTER_X(dude_ccb) < FIND_CENTER_X(target->last_hazard)) dude_ccb->ccb_XPos = target->last_hazard->ccb_XPos - (HALF_TILE_WIDTH << 16); else dude_ccb->ccb_XPos = target->last_hazard->ccb_XPos + (HALF_TILE_WIDTH << 16); if (FIND_CENTER_Y(dude_ccb) < FIND_CENTER_Y(target->last_hazard)) dude_ccb->ccb_YPos = target->last_hazard->ccb_YPos - (HALF_TILE_HEIGHT << 16); else dude_ccb->ccb_YPos = target->last_hazard->ccb_YPos + (HALF_TILE_HEIGHT << 16); test_hazard = (CCB *) NULL; test_row = -1; test_column = -1; hazards_ahoy = pavement.CheckForDanger(FIND_CENTER_X(dude_ccb),FIND_CENTER_Y(dude_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, test_row, test_column, target->last_hazard_type,test_hazard,FALSE, ((target->avoid_obstacles) && (target->breed != MEANY))); dude_ccb->ccb_XPos = old_x; dude_ccb->ccb_YPos = old_y; /* now try moving off the tile. */ if (FIND_CENTER_X(dude_ccb) < FIND_CENTER_X(target->last_hazard)) dude_ccb->ccb_XPos -= target->horz_speed; else if (FIND_CENTER_X(dude_ccb) > FIND_CENTER_X(target->last_hazard)) dude_ccb->ccb_XPos += target->horz_speed; if (FIND_CENTER_Y(dude_ccb) < FIND_CENTER_Y(target->last_hazard)) dude_ccb->ccb_YPos -= target->vert_speed; else if (FIND_CENTER_Y(dude_ccb) > FIND_CENTER_Y(target->last_hazard)) dude_ccb->ccb_YPos += target->vert_speed; /* if we're blocked, go back to where we were and give up. */ if (Obstructed(target,((target->avoid_obstacles) && (target->breed != MEANY)))) { dude_ccb->ccb_XPos = old_x; dude_ccb->ccb_YPos = old_y; target->last_hazard = (CCB *) NULL; return(FALSE); } /* Now, if there's a fire on the other side of this frying pan, then give up when */ /* we get to the edge of the frying pan and stay where we are, rather than getting */ /* stuck right between the edges of the fire and the frying pan. */ if ((hazards_ahoy) && !(pavement.AmIOnThisTile (target->last_hazard, FIND_CENTER_X(dude_ccb), FIND_CENTER_Y(dude_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1))) { dude_ccb->ccb_XPos = old_x; dude_ccb->ccb_YPos = old_y; } target->last_hazard = (CCB *) NULL; return(TRUE);}/***************************** seeker::PlanHazardDetour ******************************* This function determines the detour axis and direction, and alternate detour direction,for a seeker with hazard avoidance capabilities.*****************************************************************************************/int32 seeker::PlanHazardDetour (register dude *target, int32 dude_x, int32 dude_y){ int32 hazard_x, hazard_y; int32 center_x, center_y; int32 return_mode; /* If there's no hazard on record, then we're hosed, so just pick a random route. */ if (target->last_hazard == (CCB *) NULL) { printf("\nWarning: planning a hazard detour without a hazard... "); target->hazard_detour_axis = RandomNumber(X_AXIS,Y_AXIS); target->hazard_detour_direction = RandomNumber(PLUS_DIRECTION,MINUS_DIRECTION); target->alternate_hazard_direction = RandomNumber(PLUS_DIRECTION,MINUS_DIRECTION); return(PRIME_DETOUR); } return_mode = PRIME_DETOUR; dude_x = dude_x >> 16; dude_y = dude_y >> 16; hazard_x = target->last_hazard->ccb_XPos >> 16; hazard_y = target->last_hazard->ccb_YPos >> 16; center_x = FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb); center_y = FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb); if ((target->direction == NORTHEAST) || (target->direction == NORTHWEST) || (target->direction == SOUTHEAST) || (target->direction == SOUTHWEST)) { return_mode = HOUDINI_MODE; if (((hazard_x <= center_x) && (center_x <= hazard_x + TILE_WIDTH_25)) || ((hazard_x + TILE_WIDTH_75 <= center_x) && (center_x <= hazard_x + TILE_WIDTH))) target->hazard_detour_axis = Y_AXIS; else target->hazard_detour_axis = X_AXIS; if (target->hazard_detour_axis == X_AXIS) { if (hazard_x < dude_x) target->hazard_detour_direction = MINUS_DIRECTION; else target->hazard_detour_direction = PLUS_DIRECTION; if (dude_y > hazard_y) target->alternate_hazard_direction = MINUS_DIRECTION; else target->alternate_hazard_direction = PLUS_DIRECTION; } else /* i.e. hazard_detour_axis is Y_AXIS */ { if (dude_y > hazard_y) target->hazard_detour_direction = MINUS_DIRECTION; else target->hazard_detour_direction = PLUS_DIRECTION; if (hazard_x < dude_x) target->alternate_hazard_direction = MINUS_DIRECTION; else target->alternate_hazard_direction = PLUS_DIRECTION; } return(return_mode); } if ((target->direction == NORTH) || (target->direction == SOUTH)) target->hazard_detour_axis = X_AXIS; if ((target->direction == EAST) || (target->direction == WEST)) target->hazard_detour_axis = Y_AXIS; if (target->hazard_detour_axis == X_AXIS) { if (hazard_x > dude_x) target->hazard_detour_direction = MINUS_DIRECTION; else target->hazard_detour_direction = PLUS_DIRECTION; if (dude_y > hazard_y) target->alternate_hazard_direction = MINUS_DIRECTION; else target->alternate_hazard_direction = PLUS_DIRECTION; } else /* i.e. hazard_detour_axis is Y_AXIS */ { if (dude_y < hazard_y) target->hazard_detour_direction = MINUS_DIRECTION; else target->hazard_detour_direction = PLUS_DIRECTION; if (hazard_x < dude_x) target->alternate_hazard_direction = MINUS_DIRECTION; else target->alternate_hazard_direction = PLUS_DIRECTION; } return(return_mode);}/********************************* seeker::AtGoalEdge ********************************** The hazard-avoidance software is dependant upon the ability to sense where the edgeof a tile is, so that it can move to the edge of a tile and then move along that edge toget around a dangerous tile. This function therefore checks to see if a seeker thatis moving towards a given tile edge in a given direction has reached that edge. If theseeker has actually crossed the edge, then this function adjusts the seeker's positionslightly so that it is actually on the edge. In other words, if the seeker has overshotthe tile edge, this function shortens the seeker's move so that it moves exactly to theedge of the goal tile.*****************************************************************************************/bool seeker::AtGoalEdge (register dude *target,int32 axis,int32 direction,int32 old_x, int32 old_y){ int32 center_x, center_y, hazard_x, hazard_y; if (target->last_hazard == (CCB *) NULL) return(TRUE); center_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos >> 16; center_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos >> 16; center_x = center_x + HALF_TILE_WIDTH; center_y = center_y + HALF_TILE_HEIGHT; old_x = (old_x >> 16) + HALF_TILE_WIDTH; old_y = (old_y >> 16) + HALF_TILE_HEIGHT; hazard_x = target->last_hazard->ccb_XPos >> 16; hazard_y = target->last_hazard->ccb_YPos >> 16; /* If we've strayed out of range of the hazard, return TRUE */ if (((ABS((center_y - HALF_TILE_HEIGHT) - hazard_y)) > TILE_HEIGHT + 1) || ((ABS((center_x - HALF_TILE_WIDTH) - hazard_x)) > TILE_WIDTH + 1)) return(TRUE); if ((axis == X_AXIS) && (direction == PLUS_DIRECTION) && (old_x < (hazard_x + TILE_WIDTH)) && (center_x >= (hazard_x + TILE_WIDTH))) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->last_hazard->ccb_XPos + (TILE_WIDTH<<16) - (HALF_TILE_WIDTH<<16); return(TRUE); } if ((axis == X_AXIS) && (direction == MINUS_DIRECTION) && (old_x > hazard_x) && (center_x <= hazard_x)) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->last_hazard->ccb_XPos - (HALF_TILE_WIDTH<<16); return(TRUE); } if ((axis == Y_AXIS) && (direction == PLUS_DIRECTION) && (old_y < (hazard_y + TILE_HEIGHT)) && (center_y >= (hazard_y + TILE_HEIGHT))) { target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->last_hazard->ccb_YPos + (TILE_HEIGHT<<16) - (HALF_TILE_HEIGHT<<16); return(TRUE); } if ((axis == Y_AXIS) && (direction == MINUS_DIRECTION) && (old_y > hazard_y) && (center_y <= hazard_y)) { target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->last_hazard->ccb_YPos - (HALF_TILE_HEIGHT<<16); return(TRUE); } return(FALSE);}/**************************** seeker::ChasingWildGeese ********************************* A seeker that is busily involved in moving around a series of hazards will get soinvolved in doing so that it won't notice that the dudemeyer is no longer on the otherside of the line of hazards that its trying to go around. This function is calledperiodically therefore to make sure that the seeker is not pre-occupied in this way. Itdoes this by checking to see if the dudemeyer is no longer on the other side of the hazardcurrently being manuevered around.*****************************************************************************************/bool seeker::ChasingWildGeese (register dude *target){ int32 old_x, old_y; int32 test_row, test_column; CCB *test_hazard; int32 h,v; old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; h = 0; v = 0; test_row = target->current_row; test_column = target->current_column; while ((h < TILE_WIDTH_75) || (v < TILE_HEIGHT_75)) { HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, target->horz_speed, target->vert_speed); h += target->horz_speed >> 16; v += target->vert_speed >> 16; test_hazard = (CCB *) NULL; if (pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, test_row, test_column, target->last_hazard_type,test_hazard,FALSE,target->avoid_obstacles)) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; return(FALSE); } } target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; return (TRUE);}/****************************** seeker::TrapsLieAhead ********************************* This function is called by HandlePrimeDetourMove(), and is used to predict whether ornot a seeker will enter a dead end area if it switches into ALT_DETOUR mode at theedge of the hazard currently being maneuevered around. (For a full explanation of how thehazard-avoidance software works (and how this function fits into the big picture), goread the block comments for the BrainyMovement function.)*****************************************************************************************/bool seeker::TrapsLieAhead(register dude *target){ int32 old_x, old_y; int32 test_row, test_column; int32 alternate_axis; CCB *test_hazard; bool danger; old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; if (target->hazard_detour_axis == X_AXIS) alternate_axis = Y_AXIS; else alternate_axis = X_AXIS; /*************************************************************************************/ // First, if we're closer to dudemeyer than a tile don't worry about traps. // We also don't want to worry about traps if we aren't really on an edge. /*************************************************************************************/ if (((ABS(((old_x >> 16) + HALF_TILE_WIDTH) - SCREEN_CENTER_X)) < TILE_WIDTH) && ((ABS(((old_y >> 16) + HALF_TILE_HEIGHT) - SCREEN_CENTER_Y)) < TILE_HEIGHT)) return(FALSE); if ((((ABS(old_x - target->last_hazard->ccb_XPos)) >> 16) < (HALF_TILE_WIDTH - 2)) || (((ABS(old_y - target->last_hazard->ccb_YPos)) >> 16) < (HALF_TILE_HEIGHT - 2))) return(FALSE); /*************************************************************************************/ // Second, move half a tile on both prime and alt axes and check for hazards. /*************************************************************************************/ FollowHeading (target->walk_anim[target->direction].current_frame_ccb, target->hazard_detour_axis, target->hazard_detour_direction, HALF_TILE_WIDTH << 16, HALF_TILE_HEIGHT << 16); FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,target->alternate_hazard_direction, HALF_TILE_WIDTH << 16, HALF_TILE_HEIGHT << 16); test_hazard = (CCB *) NULL; test_row = -1; test_column = -1; danger = pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, test_row, test_column, target->last_hazard_type,test_hazard,FALSE,target->avoid_obstacles); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; if (!danger) return (FALSE); /*************************************************************************************/ // Third, move a tile on alt axis and check again. /*************************************************************************************/ FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,target->alternate_hazard_direction, TILE_WIDTH << 16, TILE_HEIGHT << 16); test_hazard = (CCB *) NULL; test_row = -1; test_column = -1; danger = pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, test_row, test_column, target->last_hazard_type,test_hazard,FALSE,target->avoid_obstacles); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; if (danger) return(TRUE); return (FALSE);}/**************************** seeker::HandleNormalMove ******************************** This function is called by BrainyMovement and handles the specifics of moving a hazard-avoiding seeker that is in NORMAL_MOVEMENT mode. (To understand what this function reallydoes and why, you need to grasp the big picture of how hazard-avoidance is handled. Thisis described fully in the block comments for the BrainyMovement function. I'm not goingto repeat it here.)*****************************************************************************************/bool seeker::HandleNormalMove(register dude *target,int32 old_x, int32 old_y){ int32 old_row, old_column; // Try moving. If we were blocked previously, and we aren't the sort of seeker that // knows how to go around obstacles, just choke up on the obstruction. On the other // hand, if we're a fast mover go slowly at first, so that if we've just come off of // a detour route we will properly handle a new encounter with a hazard. // Otherwise, dash forward at full throttle. if ((target->blocker != (solid_object *) NULL) && (target->avoid_obstacles == FALSE)) HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, (1 << 16), (1 << 16)); else if ((target->move_counter <= 2) && (target->horz_speed >= (5 << 16))) HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, (3 << 16), (3 << 16)); else HeadForTheDudemeyer(target->walk_anim[target->direction].current_frame_ccb, target->horz_speed, target->vert_speed); // Now check to see what we've stepped in. old_row = target->current_row; old_column = target->current_column; if (!(pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles))) { target->move_counter++; if (target->move_counter > 2) { target->hazard_detour_axis = NO_AXIS; target->hazard_detour_direction = NO_DIRECTION; target->alternate_hazard_direction = NO_DIRECTION; } return (TRUE); } /* We can't go this way. Go back to where we were and move into detour mode. */ target->move_status = PRIME_DETOUR; if (target->hazard_detour_axis == NO_AXIS) target->move_status = PlanHazardDetour(target, target->walk_anim[target->direction].current_frame_ccb->ccb_XPos, target->walk_anim[target->direction].current_frame_ccb->ccb_YPos); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; target->move_counter = 0; return(FALSE);}/************************** seeker::HandlePrimeDetourMove ****************************** This function is called by BrainyMovement and handles the specifics of moving a hazard-avoiding seeker that's in PRIME_DETOUR mode. (To understand what this function really doesand why, you need to grasp the big picture of how hazard-avoidance is handled. This isdescribed fully in the block comments for the BrainyMovement function. I'm not going torepeat it here.)*****************************************************************************************/bool seeker::HandlePrimeDetourMove(register dude *target,int32 old_x, int32 old_y){ int32 alternate_axis; bool danger; int32 old_row, old_column; if (target->hazard_detour_axis == NO_AXIS) target->move_status = PlanHazardDetour(target,old_x,old_y); if (target->move_status != PRIME_DETOUR) return(FALSE); /* Really fast seekers sometimes get stuck in tight spots between pairs of hazards */ /* nearby pyramids. Therefore, if there's an obstruction here in addition to the */ /* hazards, and we're a fast seeker, we must slow down a bit. */ if ((target->blocker != (solid_object *) NULL) && ((target->breed == LURKER) || (target->breed == ACTIVE_REDCOAT))) FollowHeading (target->walk_anim[target->direction].current_frame_ccb, target->hazard_detour_axis, target->hazard_detour_direction, (5 << 16), (3 << 16)); else FollowHeading (target->walk_anim[target->direction].current_frame_ccb, target->hazard_detour_axis, target->hazard_detour_direction, target->horz_speed, target->vert_speed); // Now check to see what we've stepped in. old_row = target->current_row; old_column = target->current_column; if (pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles)) { target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; // See if it will work to switch to the alt axis; if it won't, go into Houdini mode. if (target->hazard_detour_axis == X_AXIS) alternate_axis = Y_AXIS; else alternate_axis = X_AXIS; FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,target->alternate_hazard_direction, target->horz_speed,target->vert_speed); danger = pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; if (!danger) { target->move_status = ALT_DETOUR; return(FALSE); } // OK, that won't work. Now let's try the alt axis but in the other direction. if (target->alternate_hazard_direction == PLUS_DIRECTION) target->alternate_hazard_direction = MINUS_DIRECTION; else target->alternate_hazard_direction = PLUS_DIRECTION; FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,target->alternate_hazard_direction, target->horz_speed,target->vert_speed); danger = pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; if (!danger) { target->move_status = ALT_DETOUR; return(FALSE); } target->move_status = HOUDINI_MODE; if (target->hazard_detour_axis == Y_AXIS) target->hazard_detour_axis = X_AXIS; else target->hazard_detour_axis = Y_AXIS; target->alternate_hazard_direction = target->hazard_detour_direction; target->hazard_detour_direction = RandomNumber(PLUS_DIRECTION,MINUS_DIRECTION); return(FALSE); } if (target->last_hazard == (CCB *) NULL) { target->move_status = NORMAL_MOVEMENT; return(TRUE); } if (AtGoalEdge(target, target->hazard_detour_axis, target->hazard_detour_direction, old_x, old_y)) { target->move_status = ALT_DETOUR; if (TrapsLieAhead(target)) target->move_status = PRIME_DETOUR; if (ChasingWildGeese(target)) target->move_status = NORMAL_MOVEMENT; } return(TRUE);}/*************************** seeker::HandleAltDetourMove ******************************* This function is called by BrainyMovement and handles the specifics of moving a hazard-avoiding seeker that is in ALT_DETOUR mode. (To understand what this function really doesand why, you need to grasp the big picture of how hazard-avoidance is handled. This isdescribed fully in the block comments for the BrainyMovement function. I'm not going torepeat it here.)*****************************************************************************************/bool seeker::HandleAltDetourMove(register dude *target,int32 old_x, int32 old_y){ int32 alternate_axis; int32 old_row, old_column; if (target->hazard_detour_axis == X_AXIS) alternate_axis = Y_AXIS; else alternate_axis = X_AXIS; /* Really fast seekers sometimes get stuck in tight spots between pairs of hazards */ /* nearby pyramids. Therefore, if there's an obstruction here in addition to the */ /* hazards, and we're a fast seeker, we must slow down a bit. */ if ((target->blocker != (solid_object *) NULL) && ((target->breed == LURKER) || (target->breed == ACTIVE_REDCOAT))) FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,target->alternate_hazard_direction, (5 << 16), (3 << 16)); else FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,target->alternate_hazard_direction, target->horz_speed,target->vert_speed); old_row = target->current_row; old_column = target->current_column; if (!(pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles))) { if (AtGoalEdge(target, alternate_axis,target->alternate_hazard_direction, old_x, old_y)) target->move_status = NORMAL_MOVEMENT; return(TRUE); } target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; /* There's a new hazard in our way. Try switching back to the detour route. */ FollowHeading (target->walk_anim[target->direction].current_frame_ccb, target->hazard_detour_axis, target->hazard_detour_direction, target->horz_speed, target->vert_speed); if (!(pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles))) { /* OK, the prime detour route is OK. Switch modes. */ target->move_status = PRIME_DETOUR; return(TRUE); } // Uh-oh! That move was also hazard-ridden. We're trapped. Go back the way we came. target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; target->move_status = HOUDINI_MODE; return(FALSE);}/**************************** seeker::HandleHoudiniMove ******************************** This function is called by BrainyMovement and handles the specifics of moving a hazard-avoiding seeker that is in HOUDINI_MODE. (To understand what this function really doesand why, you need to grasp the big picture of how hazard-avoidance is handled. This isdescribed fully in the block comments for the BrainyMovement function. I'm not going torepeat it here.)*****************************************************************************************/bool seeker::HandleHoudiniMove(register dude *target,int32 old_x, int32 old_y){ int32 alternate_axis; int32 alternate_direction; int32 old_row, old_column; if (target->hazard_detour_axis == X_AXIS) alternate_axis = Y_AXIS; else alternate_axis = X_AXIS; if (target->alternate_hazard_direction == PLUS_DIRECTION) alternate_direction = MINUS_DIRECTION; else alternate_direction = PLUS_DIRECTION; /* Really fast seekers sometimes get stuck in tight spots between pairs of hazards */ /* nearby pyramids. Therefore, if there's an obstruction here in addition to the */ /* hazards, and we're a fast seeker, we must slow down a bit. */ if ((target->blocker != (solid_object *) NULL) && ((target->breed == LURKER) || (target->breed == ACTIVE_REDCOAT))) FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,alternate_direction, (5 << 16), (3 << 16)); else FollowHeading (target->walk_anim[target->direction].current_frame_ccb, alternate_axis,alternate_direction, target->horz_speed,target->vert_speed); old_row = target->current_row; old_column = target->current_column; if (pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles)) { if (target->hazard_detour_axis == Y_AXIS) target->hazard_detour_axis = X_AXIS; else target->hazard_detour_axis = Y_AXIS; target->alternate_hazard_direction = target->hazard_detour_direction; target->hazard_detour_direction = RandomNumber(PLUS_DIRECTION,MINUS_DIRECTION); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; return(FALSE); } if (AtGoalEdge(target, alternate_axis, alternate_direction, old_x, old_y)) { target->move_status = PRIME_DETOUR; if (ChasingWildGeese(target)) target->move_status = NORMAL_MOVEMENT; } return(TRUE);}/***************************** seeker::BrainyMovement ********************************* This function handles the movement abilities for seekers who are smart enough to steeraround hazards. It also handles both those who can't get out from behind obstacles andthose who can. The first thing we do is to check to see if we are already standing on a hazard. (If we are, we ignore all else and jump off the tile in the most direct way possible.) Afterthis, we move in accordance with the movement mode we are in. As we encounter hazards, wewill end up in one of 4 different movement modes, and for each mode, we call a functionthat moves our seeker appropriately for that mode. The four modes are as follows: NORMAL_MOVEMENT: Performed by the function HandleNormalMove(). ============================================================== This is the standard mode. In this mode we move towards the objective in the most direct way we can. If a hazard appears in our path, however, we switch to PRIME_DETOUR mode. If an object appears in our path, we move around it if we are the sort of seeker who can do that. PRIME_DETOUR: Performed by the function HandlePrimeDetourMove(). =================================================================== In this mode, we don't try to move towards the objective, we instead move along a predefined detour route (axis and direction). (If no detour route has yet been chosen, PlanHazardDetour is called to pick one.) We continue moving along the Prime detour path, i.e. along the edge of the hazard, until we reach the corner, at which point we switch into ALT_DETOUR mode, which carries us along the other edge of the hazard, on a path perpendicular to the prime detour path. That is, except in two situations. If we're moving along a line of pits, and the ALT_DETOUR path is just going to carry us down into a dead end (i.e. a trap), then we continue on the prime detour path until we get to the next hazard edge. (The task of predicting that ALT_DETOUR will send us into a trap is handled by the function TrapsLieAhead().) Also, if the objective point has moved enough since we started on this detour that it no longer makes sense to continue on this detour, then we stop what we're doing and go back to NORMAL_MOVEMENT mode. (Determining that the detour no longer makes sense is the job of the function ChasingWildGeese().) ALT_DETOUR: Performed by the function HandleAltDetourMove(). ================================================================= As indicated above, this mode is a follow through of the movements taken in PRIME_DETOUR mode. The only way to get into this mode is to be moving along the Prime detour path and to reach the edge of a hazard. From there, we move along the secondary edge of the hazard, after which, we'll have presumably gotten past the hazard we were trying to go around. If this is true, we go back to NORMAL mode. However, it ain't always so easy. Sometimes we will run into another hazard. This will occur in either of 2 cases. If we are trying to get past a diagonal line of hazards, we'll hit a new one when we get past the current one and we'll need to go back into PRIME_DETOUR mode to get past it. Alternatively, if we've gone into a dead end, PRIME_DETOUR won't help us... we have no choice but to go back the way we came. In this case, we switch into HOUDINI_MODE. HOUDINI_MODE: Performed by the function HandleHoudiniMove(). =============================================================== This mode is used when we need to back out of a trap. In this mode we move backwards along the ALT_DETOUR axis until we get to the edge of the tile that led us into the trap, at which point we go back into PRIME_DETOUR mode. We also call ChasingWildGeese at this transition point to make sure we aren't sticking to a useless detour. Note that when PRIME_DETOUR mode is entered for the first time, a detour route is selected and kept with for as long as we are trying to maneuver around hazards. It'simportant to maintain this fixity of purpose because if we're going around a line ofpits, we need to keep going in the direction we start out in or we'll just go back andforth without getting anywhere. Thus, we pick our detour direction and keep moving alongit until we get out into open space and are able to move freely for a long enough timeto conclude that if we get blocked again it'll be a whole new problem. Once this happens,we zero out our stored detour route, forcing us to select a new detour route the nexttime we get blocked. After we make our hazard-conscious move, we then check to see if we ran into a solidobject of some sort. If we did, and we aren't smart enough to go around obstacles, wego back to where we were and give up. However, if we are smart enough to go aroundobstacles, we then call AvoidObstruction to move us around the object in question.However, this may have the effect of moving us into a dangerous spot, so as soon as we'vemoved, we check the ground we're on again and move back off of it if it's hazardous. Atthis time, we also change our hazard avoidance state.*****************************************************************************************/bool seeker::BrainyMovement (register dude *target){ int32 old_x, old_y; int32 old_row, old_column; bool move_result; //solid_object *old_obstruction; int32 horz_obj_avoid_speed; int32 vert_obj_avoid_speed; //old_obstruction = target->blocker; old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; old_row = target->current_row; old_column = target->current_column; move_result = TRUE; // Before trying to move, check for immediate hazards and run away if in danger. if (pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE,FALSE)) return (RunAway(target)); switch (target->move_status) { case NORMAL_MOVEMENT: move_result = HandleNormalMove(target, old_x, old_y); break; case PRIME_DETOUR: move_result = HandlePrimeDetourMove(target, old_x, old_y); break; case ALT_DETOUR: move_result = HandleAltDetourMove(target, old_x, old_y); break; case HOUDINI_MODE: move_result = HandleHoudiniMove(target, old_x, old_y); break; } if (move_result == FALSE) return(FALSE); if (!(Obstructed(target,((target->avoid_obstacles) && (target->breed != MEANY))))) { /* if we've moved once, set the stale detour flags to the current detour flags */ if (target->obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = target->obstacle_detour_axis; target->obstacle_detour_axis = NO_AXIS; } /* if we've moved successfully twice in a row, clear out the stale detour flags */ else if (target->old_obstacle_detour_axis != NO_AXIS) { target->old_obstacle_detour_axis = NO_AXIS; } return(TRUE); } else { if (target->avoid_obstacles == FALSE) { target->move_counter = 0; target->move_status = NORMAL_MOVEMENT; /* It often happens that a pair of non-object-avoiding seekers will get stuck */ /* on each other, and it looks dumb when it happens. Thus, we give a tiny bit */ /* of smarts to these guys: They can avoid other seekers. */ if ((target->blocker->object_type >= FIRST_SEEKER) && (target->blocker->object_type <= LAST_SEEKER)) return (AvoidObstruction(target,old_x,old_y, RandomNumber(0,target->horz_speed), RandomNumber(0,target->vert_speed))); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; return(FALSE); } // Have we run into another obstacle while already in the process of avoiding one? // At the moment, I have no strategy for handling this situation. //if ((old_obstruction != (solid_object *) NULL) // && (old_obstruction != target->blocker)) //{ //} /* Really fast seekers sometimes get stuck when dealing with object avoidance. */ /* Therefore, we slow them down during object avoidance. */ horz_obj_avoid_speed = target->horz_speed; if (horz_obj_avoid_speed > (3 << 16)) horz_obj_avoid_speed = (3 << 16); vert_obj_avoid_speed = target->vert_speed; if (vert_obj_avoid_speed > (3 << 16)) vert_obj_avoid_speed = (3 << 16); if ((target->blocker->object_type >= FIRST_SEEKER) && (target->blocker->object_type <= LAST_SEEKER)) move_result = AvoidObstruction(target,old_x,old_y, RandomNumber(0,horz_obj_avoid_speed), RandomNumber(0,vert_obj_avoid_speed)); else move_result = AvoidObstruction(target,old_x,old_y,horz_obj_avoid_speed, vert_obj_avoid_speed); } if (move_result == FALSE) return(FALSE); if (!(pavement.CheckForDanger( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1, target->current_row, target->current_column, target->last_hazard_type,target->last_hazard,FALSE, target->avoid_obstacles))) return (TRUE); /* We can't go this way. Go back to where we were and move into detour mode. */ if (target->immobile_counter >= 2) { if (target->obstacle_detour_direction == MINUS_DIRECTION) target->obstacle_detour_direction = PLUS_DIRECTION; else target->obstacle_detour_direction = MINUS_DIRECTION; } if (target->immobile_counter >= 5) target->move_status = RandomNumber(NORMAL_MOVEMENT,HOUDINI_MODE); else target->move_status = PRIME_DETOUR; if (target->hazard_detour_axis == NO_AXIS) target->move_status = PlanHazardDetour(target, target->walk_anim[target->direction].current_frame_ccb->ccb_XPos, target->walk_anim[target->direction].current_frame_ccb->ccb_YPos); target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = old_x; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = old_y; target->current_row = old_row; target->current_column = old_column; target->move_counter = 0; return(FALSE);}/***************************** seeker::HeadForTheDudemeyer ***************************** This function is the driver that sends a seeker on a beeline route to the center of thescreen, i.e. towards the dudemeyer.*****************************************************************************************/void seeker::HeadForTheDudemeyer (register CCB *target,int32 horz_speed,int32 vert_speed){ int32 center_x, center_y; center_x = FIND_CENTER_X(target); if (center_x != SCREEN_CENTER_X) { if (center_x > SCREEN_CENTER_X) { if ((ABS(center_x - SCREEN_CENTER_X)) << 16 < horz_speed) target->ccb_XPos = (SCREEN_CENTER_X - HALF_TILE_WIDTH) << 16; else target->ccb_XPos -= horz_speed; } else { if ((ABS(center_x - SCREEN_CENTER_X)) << 16 < horz_speed) target->ccb_XPos = (SCREEN_CENTER_X - HALF_TILE_WIDTH) << 16; else target->ccb_XPos += horz_speed; } } center_y = FIND_CENTER_Y(target); if (center_y != SCREEN_CENTER_Y) { if (center_y > SCREEN_CENTER_Y) { if ((ABS(center_y - SCREEN_CENTER_Y)) << 16 < vert_speed) target->ccb_YPos = (SCREEN_CENTER_Y - HALF_TILE_HEIGHT) << 16; else target->ccb_YPos -= vert_speed; } else { if ((ABS(center_y - SCREEN_CENTER_Y)) << 16 < vert_speed) target->ccb_YPos = (SCREEN_CENTER_Y - HALF_TILE_HEIGHT) << 16; else target->ccb_YPos += vert_speed; } }}/***************************** seeker::FollowHeading ********************************** This function takes an axis identifier, a plus or minus direction, and a movement rate, and then adjusts the specified CCB to move the specified distance along the specified axis in the specified direction.*****************************************************************************************/void seeker::FollowHeading (register CCB *target, int32 axis, int32 direction, int32 x_change, int32 y_change){ if ((axis == X_AXIS) && (direction == PLUS_DIRECTION)) target->ccb_XPos += x_change; if ((axis == X_AXIS) && (direction == MINUS_DIRECTION)) target->ccb_XPos -= x_change; if ((axis == Y_AXIS) && (direction == PLUS_DIRECTION)) target->ccb_YPos += y_change; if ((axis == Y_AXIS) && (direction == MINUS_DIRECTION)) target->ccb_YPos -= y_change;}/************************* seeker::CommenceHazardDeath ******************************** When a seeker first falls into a pit (or other hazardous tile), this function is called to perform some transitions functions for that seeker. Depending on the nature of the tile, the state of the seeker will be altered to reflect that the seeker is being killed off by coming into contact with the hazardous tile. The appearance of the seeker is also changed from being an animation of the seeker moving to a static view of the seeker just before the appropriate death animation begins.*****************************************************************************************/void seeker::CommenceHazardDeath(register dude *target){ if ((target->last_hazard_type >= FIRST_PITFORMATION) && (target->last_hazard_type <= LAST_PITFORMATION)) return; if (pavement.IsSlimeOrLavaComingSoon(target->current_row,target->current_column,TRUE)) return; if ((target->last_hazard_type == PA_TILE) || (target->last_hazard_type == PB_TILE) || (target->last_hazard_type == PD_TILE) || (target->last_hazard_type == PE_TILE) || (target->last_hazard_type == PF_TILE) || (target->last_hazard_type == PC_TILE) || (target->last_hazard_type == PG_TILE) || (target->last_hazard_type == PH_TILE) || (target->last_hazard_type == PI_TILE) || (target->last_hazard_type == P1_TILE) || (target->last_hazard_type == PJ_TILE) || (target->last_hazard_type == PL_TILE) || (target->last_hazard_type == PM_TILE)) { target->health = STUMBLING; if (ObjectVisible(target->last_hazard)) PlaySoundEffect(FALLING_SOUND); target->stumbling.current_frame_ccb->ccb_XPos = target->solids_entry->cel->ccb_XPos; target->stumbling.current_frame_ccb->ccb_YPos = target->solids_entry->cel->ccb_YPos; target->solids_entry->cel = target->stumbling.current_frame_ccb; return; } if ((target->last_hazard_type == LA_TILE) || (target->last_hazard_type == LB_TILE) || (target->last_hazard_type == L1_TILE)) { target->health = CONSUMED_BY_LAVA; return; } /* We shouldn't get to this point, but sometimes we do. On returning from here, we */ /* will use the function RunAway to try to get off of the tile were on, which can */ /* only be the tile under a rock which is being regarded as hazardous. If this */ /* doesn't work, then it means we've somehow gotten wedged inside of a rock. In */ /* this unpleasant situation, the best thing to do is just vanish and die. */ if (target->stranded_counter > 3) { SendHome(target); printf("$"); }}/********************** seeker::CheckForSeekerHazardDeaths **************************** This function is used when the game is about to end, when we wish to let allin-progress death animations play themselves out. The MaintainMorgue function (in the dead_list class) takes care of keeping real death animations going until they're done, but if a seeker has started falling into a pit, but hasn't yet kicked off a death animation, then the MaintainMorgue function won't know about it. This function therefore goes through the list of seekers and returns TRUE if any seekers are in still in the process of falling into a pit (or other such tile-based hazard).*****************************************************************************************/bool seeker::CheckForSeekerHazardDeaths(void){ register dude *target; bool return_value; return_value = FALSE; target = seeker_list; while (target != (dude *) NULL) { if ((target->health == STUMBLING) || (target->health == CONSUMED_BY_LAVA)) { if (PullIntoHazard(target)) /* If something was eliminated from the list */ target = seeker_list; /* then our pointer into the list is invalid.*/ /* Thus, we start the list traversal over. */ return_value = TRUE; } target = target->next; } return(return_value);}/****************************** seeker::PullIntoHazard ******************************** When a seeker gets close enough to a pit (or other tile-based hazard) to fall in, itbecomes necessary to bridge the visual gap between the first frame of thefalling-into-a-pit animation (which depicts the seeker falling into the pit from aposition directly over the center of the pit) and the actual current location of theseeker (which can be at just about any point along any edge of the hazard in question).This routine takes care of that. It is called by AnimateSeekers whenever a seeker's stateis set to indicate that it's falling into a pit (or similar hazard) and on each pass, theseeker is shown in successive positions, growing gradually closer to the center of thehazard, until the seeker is centered over the tile, at which point this routine callsforth the seeker's death animation and sends the seeker home.*****************************************************************************************/bool seeker::PullIntoHazard (register dude *target){ int32 x,y; if (target->last_hazard == (CCB *) NULL) { printf("No hazard! We're heading for a crash!\n"); target->health = NOT_DEAD; return(TRUE); } if (target->health == STUMBLING) target->stumbling.AdvanceFrame(); /******** The following lines added 9/5/95 to fix the zombie fire walk bug. **********/ x = FIND_CENTER_X(target->solids_entry->cel) - FIND_CENTER_X(target->last_hazard); y = FIND_CENTER_Y(target->solids_entry->cel) - FIND_CENTER_Y(target->last_hazard); if (((ABS(x)) >= TILE_WIDTH) || ((ABS(y)) >= TILE_HEIGHT)) { target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->stumbling.Restart(); if (ObjectVisible(target->solids_entry->cel)) target->health = NOT_DEAD; else SendHome(target); return(TRUE); } /************************** zombie fire walk patch complete **************************/ if ( (GravitateTowardsPoint(target->solids_entry->cel, 5, FIND_CENTER_X(target->last_hazard), FIND_CENTER_Y(target->last_hazard)))) { if (target->breed == YELLOW_SEEKER) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&yellow_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&yellow_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if ((target->breed == LTBLUE_SEEKER) || (target->breed == ACTIVE_BUMMER)) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (<blue_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (<blue_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if ((target->breed == LIME_SEEKER) || (target->breed == ACTIVE_CHAMELEON)) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&lime_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&lime_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == PINK_SEEKER) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&pink_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&pink_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == ZOMBIE) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; switch(target->special) { case 1: morgue.CreateDeathScene (&zombie1pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); break; case 2: morgue.CreateDeathScene (&zombie2pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); break; case 3: morgue.CreateDeathScene (&zombie3pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); break; } } if (target->health == CONSUMED_BY_LAVA) { switch(target->special) { case 1: morgue.CreateDeathScene (&zombie1lava_death,STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); break; case 2: morgue.CreateDeathScene (&zombie2lava_death,STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); break; case 3: morgue.CreateDeathScene (&zombie3lava_death,STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); break; } } } if ((target->breed == LURKER) || (target->breed == ACTIVE_REDCOAT)) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&lurker_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&lurker_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == MEANY) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&meany_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&meany_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == NASTY) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&nasty_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&nasty_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == GRUMPY) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&grumpy_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&grumpy_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == JUGGERNAUT) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&jugger_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&jugger_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if (target->breed == PSYCHO) { if (target->health == STUMBLING) { target->health = FELL_INTO_A_PIT; morgue.CreateDeathScene (&psycho_pit_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0, target->stumbling.current_frame_number); } if (target->health == CONSUMED_BY_LAVA) { morgue.CreateDeathScene (&psycho_lava_death, STANDARD_FRAME_RATE, target->last_hazard->ccb_XPos, target->last_hazard->ccb_YPos,0,0,0); } } if ((target->health == CONSUMED_BY_LAVA) && (ObjectVisible(target->last_hazard))) PlaySoundEffect(LAVA_SIZZLE_SOUND); target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->stumbling.Restart(); SendHome(target); return(TRUE); } else return(FALSE);}/**************************** seeker::CheckChameleonProximity ************************** This function is used to find out if a Chameleon seeker is close enough to the centerof the screen (i.e. to the dudemeyer) to come out of hiding and attack.*****************************************************************************************/bool seeker::CheckChameleonProximity(CCB *seeker_cel){ int32 current_x, current_y; current_x = FIND_CENTER_X(seeker_cel); current_y = FIND_CENTER_Y(seeker_cel); if ((current_x < SCREEN_CENTER_X + CHAMELEON_RANGE_X) && (current_x > SCREEN_CENTER_X - CHAMELEON_RANGE_X) && (current_y < SCREEN_CENTER_Y + CHAMELEON_RANGE_Y) && (current_y > SCREEN_CENTER_Y - CHAMELEON_RANGE_Y)) return(TRUE); return(FALSE);}/**************************** seeker::MaintainChameleon ******************************* This function is called for performing needed upkeep on Chameleons that haven'tbecome active yet. For dormant Chameleons, we check to see if the dudemeyer is closeenough to cause them to wake up; for waking up Chameleons, the process of waking up iscarried out.*****************************************************************************************/void seeker::MaintainChameleon (register dude *target){ if ((target->breed == WAKING_CHAMELEON) || (target->breed == WAKING_BUMMER) || (target->breed == WAKING_REDCOAT)) { target->special_anim.AdvanceFrame(); if (target->special_anim.AnimComplete()) { g_total_pyramids--; target->solids_entry->cel=target->walk_anim[target->direction].current_frame_ccb; target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->special_anim.current_frame_ccb->ccb_XPos; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->special_anim.current_frame_ccb->ccb_YPos; if (target->breed == WAKING_CHAMELEON) { target->breed = ACTIVE_CHAMELEON; target->solids_entry->object_type = ACTIVE_CHAMELEON; } if (target->breed == WAKING_BUMMER) { target->breed = ACTIVE_BUMMER; target->solids_entry->object_type = ACTIVE_BUMMER; } if (target->breed == WAKING_REDCOAT) { target->breed = ACTIVE_REDCOAT; target->solids_entry->object_type = ACTIVE_REDCOAT; target->special_anim.ShutdownForRestart(); target->special_anim.InitializeAnim (&lurker_wait, STANDARD_FRAME_RATE); target->special_anim.Restart(); target->special = 1; } } return; } /* if it's a dormant chameleon, check to see if we are close to it. */ if (CheckChameleonProximity(target->special_anim.current_frame_ccb)) { PlaySoundEffect(CHAM_ACTIVIATION_SOUND); target->special_anim.AdvanceFrame(); if (target->breed == DORMANT_CHAMELEON) { target->breed = WAKING_CHAMELEON; target->solids_entry->object_type = WAKING_CHAMELEON; } if (target->breed == DORMANT_REDCOAT) { target->breed = WAKING_REDCOAT; target->solids_entry->object_type = WAKING_REDCOAT; } if (target->breed == DORMANT_BUMMER) { target->breed = WAKING_BUMMER; target->solids_entry->object_type = WAKING_BUMMER; } }}/******************************* seeker::ReviveZombie ********************************** Since Zombies are (usually) inserted into the game in a different way from mostseekers, we need a special routine to handle their appearance. This function allows azombie to emerge from the center of its home tile, on screen, for all eyes to see, insteadof simply appearing invisibly out in the wasteland and marching in. But doing thisrequires two special tasks: First, we need to make sure the coast is clear (we can onlyemerge from a tile if there's nothing currently on the tile; otherwise, we'd collide andcause all sorts of questions); and secondly, we need to play a special animation thatshows the zombie actually materializing. Additionally, if it has somehow occurred (throughan error on the part of the level designer or simply through randomly selecting a swamptile for our home) that our home time is obstructed by something that will never allow usto emerge (such as a rock, or a purple pyramid that would cause a pit to occupy our tile,which we cannot logically emerge from), then we randomly select a new tile to be our home. We use the special field in our seeker info entry to determine our state, as follows: -1 or less: In limbo, waiting to be reborn. 0: In the process of emerging from a swamp tile. 1: A strong and healthy zombie. 2: A zombie with one wound. 3: A zombie with two wounds. 4: A dead zombie.*****************************************************************************************/void seeker::ReviveZombie (register dude *target){ int32 i; CCB *tile; if (target->special < 0) { target->special++; if (target->special == 0) { tile = pavement.FetchTileCCB(target->home_row,target->home_column); target->blocker = population.DetectCollision (tile, target->solids_entry->col_detect_x, target->solids_entry->col_detect_y, FALSE); if (target->blocker != (solid_object *) NULL) { if (((target->blocker->object_type >= FIRST_BOULDER) && (target->blocker->object_type <= LAST_BOULDER)) || (target->blocker->object_type == SLIMY_PYRAMID) || (target->blocker->object_type == STEEL_PYRAMID) || (target->blocker->object_type == PURPLE_PYRAMID) || (target->blocker->object_type == RAINBOW_PYRAMID)) { pavement.SelectSwampAtRandom(target->home_row,target->home_column); target->special = -1; return; } else if (target->blocker->object_type == GREEN_PYRAMID) { PlaySoundEffect(PULVERIZE_SOUND); morgue.CreateDeathScene (&population.green_death, STANDARD_FRAME_RATE, target->blocker->cel->ccb_XPos, target->blocker->cel->ccb_YPos, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y,0); population.EliminateObject(target->blocker); g_total_pyramids--; target->blocker = (solid_object *) NULL; } else { target->special = -1; return; } } target->special_anim.current_frame_ccb->ccb_XPos = tile->ccb_XPos; target->special_anim.current_frame_ccb->ccb_YPos = tile->ccb_YPos; population.AddToList(target->special_anim.current_frame_ccb, BIRTH_SCENE, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); /* if we're still at the zero point, then it's time to play the birth sound. */ if (target->special == 0) PlaySoundEffect(ZOMBIE_BIRTH_SOUND); } } if (target->special == 0) { target->special_anim.AdvanceFrame(); if (target->special_anim.AnimComplete()) { target->special = 1; for (i = 0; i < 8; i++) { target->walk_anim[i].Restart(); target->walk_anim[i].current_frame_ccb->ccb_XPos = target->special_anim.current_frame_ccb->ccb_XPos; target->walk_anim[i].current_frame_ccb->ccb_YPos = target->special_anim.current_frame_ccb->ccb_YPos; } population.EliminateObject(target->special_anim.current_frame_ccb); } }}/**************************** seeker::DealWithSwamp *********************************** When a seeker wanders onto a swamp tile, its speed is affected. Most seekers areslowed by moving through swamps (although zombies actually speed up) and so it becomesnecessary for us to change the seeker's speed values if they enter a swamp. First, ofcourse, we check to see if we are in a swamp, and then, if we are, we change the speedsettings accordingly. These changes wear off (by calling SetSeekerSpeeds to reset themto normal) after the seeker moves out of the swamp and enough time passes for the effectsto fade away (i.e. until after it moves out of the ambiguous area between tiles, whichwe sense crudely by keeping the slowness around for several game cycles).*****************************************************************************************/void seeker::DealWithSwamp(register dude *target){ if (pavement.CheckForSwamp( FIND_CENTER_X(target->walk_anim[target->direction].current_frame_ccb), FIND_CENTER_Y(target->walk_anim[target->direction].current_frame_ccb), target->solids_entry->col_detect_x + 1, target->solids_entry->col_detect_y + 1)) { target->bogged_down_in_swamp = 5; switch (target->breed) { case ZOMBIE: target->horz_speed = 0x00022500; /* i.e. 2.25 */ target->vert_speed = 0x00022500; /* i.e. 2.25 */ break; case YELLOW_SEEKER: case PINK_SEEKER: case LTBLUE_SEEKER: case LIME_SEEKER: case MEANY: case NASTY: case GRUMPY: case JUGGERNAUT: case PSYCHO: case ACTIVE_CHAMELEON: case ACTIVE_BUMMER: target->horz_speed = 0x00017500; /* i.e. 1.75 */ target->vert_speed = 0x00017500; /* i.e. 1.75 */ break; case ACTIVE_REDCOAT: case LURKER: target->horz_speed = 0x00040000; /* i.e. 4 */ target->vert_speed = 0x00030000; /* i.e. 3 */ break; } } if (target->bogged_down_in_swamp) { target->bogged_down_in_swamp--; if (target->bogged_down_in_swamp == 0) SetSeekerSpeeds(target); }}/****************************** seeker::ShootZombie ************************************ Since Zombies are not destroyed instantly but require 3 shots, we need a specialroutine that the weapon class can use to deal with the impact on a zombie that gettingshot causes. On the first 2 shots, a sound is played and the animation is switched tothe next stage of the zombie's detoritation; on the final shot, the zombie is killed. We use the special field in our seeker info entry to determine our state, as follows: -1 or less: In limbo, waiting to be reborn. 0: In the process of emerging from a swamp tile. 1: A strong and healthy zombie. 2: A zombie with one wound. 3: A zombie with two wounds. 4: A dead zombie.*****************************************************************************************/void seeker::ShootZombie(register solid_object *target){ dude *zombie; zombie = seeker_list; while (zombie != (dude *) NULL) { if (zombie->solids_entry == target) { zombie->special++; if (zombie->special == 2) { PlaySoundEffect(ZOMBIE_HIT_SOUND); zombie->walk_anim[EAST].ChangeArt (&zombie2_walk_e); zombie->walk_anim[NORTHEAST].ChangeArt (&zombie2_walk_ne); zombie->walk_anim[NORTHWEST].ChangeArt (&zombie2_walk_nw); zombie->walk_anim[NORTH].ChangeArt (&zombie2_walk_n); zombie->walk_anim[SOUTH].ChangeArt (&zombie2_walk_s); zombie->walk_anim[SOUTHEAST].ChangeArt (&zombie2_walk_se); zombie->walk_anim[SOUTHWEST].ChangeArt (&zombie2_walk_sw); zombie->walk_anim[WEST].ChangeArt (&zombie2_walk_w); zombie->stumbling.ChangeArt(&zombie2pit_death); zombie->walk_anim[zombie->direction].RefetchFrame(); morgue.CreateDeathScene (&zombie_shrapnel, STANDARD_FRAME_RATE, target->cel->ccb_XPos,target->cel->ccb_YPos,0,0,0); } if (zombie->special == 3) { PlaySoundEffect(ZOMBIE_HIT_SOUND); zombie->walk_anim[EAST].ChangeArt (&zombie3_walk_e); zombie->walk_anim[NORTHEAST].ChangeArt (&zombie3_walk_ne); zombie->walk_anim[NORTHWEST].ChangeArt (&zombie3_walk_nw); zombie->walk_anim[NORTH].ChangeArt (&zombie3_walk_n); zombie->walk_anim[SOUTH].ChangeArt (&zombie3_walk_s); zombie->walk_anim[SOUTHEAST].ChangeArt (&zombie3_walk_se); zombie->walk_anim[SOUTHWEST].ChangeArt (&zombie3_walk_sw); zombie->walk_anim[WEST].ChangeArt (&zombie3_walk_w); zombie->stumbling.ChangeArt(&zombie3pit_death); zombie->walk_anim[zombie->direction].RefetchFrame(); morgue.CreateDeathScene (&zombie_shrapnel, STANDARD_FRAME_RATE, target->cel->ccb_XPos,target->cel->ccb_YPos,0,0,0); } if (zombie->special == 4) { PlaySoundEffect(ZOMBIE_DEATH_SOUND); morgue.CreateDeathScene (&zombie_death, STANDARD_FRAME_RATE, target->cel->ccb_XPos,target->cel->ccb_YPos, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y,0); SendHome(zombie); } return; } zombie = zombie->next; } printf("Danger Will Robinson! Failure in attempt to shoot a Zombie!\n");}/****************************** seeker::ShootSplitter ********************************** The process of shooting many types of seekers is very simple and can be handleddirectly by the weapon class. However, since Meanies and Nasties don't die, but insteadsplit into smaller seekers when shot, the task of dealing with them is a bit morecomplex. This function takes care of the special handling involved.*****************************************************************************************/void seeker::ShootSplitter(register solid_object *target){ dude *mom; mom = seeker_list; while (mom != (dude *) NULL) { if (mom->solids_entry == target) { if (mom->health != NOT_DEAD) return; if ((mom->breed == MEANY) || (mom->breed == NASTY)) { /* insert the splitting anim where the piece is */ mom->special_anim.current_frame_ccb->ccb_XPos = mom->walk_anim[mom->direction].current_frame_ccb->ccb_XPos; mom->special_anim.current_frame_ccb->ccb_YPos = mom->walk_anim[mom->direction].current_frame_ccb->ccb_YPos; if (mom->breed == MEANY) population.AddToList(mom->special_anim.current_frame_ccb, SPLIT_SCENE, PYRAMID_COL_DETECT_X + 2, PYRAMID_COL_DETECT_Y + 2); if (mom->breed == NASTY) population.AddToList(mom->special_anim.current_frame_ccb, SPLIT_SCENE, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y); mom->blocker = population.FindPointerIntoList (mom->special_anim.current_frame_ccb); /* now hide the walk anims way off screen: */ mom->walk_anim[mom->direction].current_frame_ccb->ccb_XPos = 0xFFF0000; mom->walk_anim[mom->direction].current_frame_ccb->ccb_YPos = 0xFFF0000; population.FixPositionOnList(mom->solids_entry); PlaySoundEffect(ORANGE_HIT_SOUND); mom->health = SPLITTING_STASIS; mom->special = -1; return; } if (mom->breed == GRUMPY) { PlaySoundEffect(ORANGE_HIT_SOUND); mom->health = DEAD; morgue.CreateDeathScene (&grumpy_death, STANDARD_FRAME_RATE, target->cel->ccb_XPos,target->cel->ccb_YPos, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y,0); SendHome(mom); return; } } mom = mom->next; } printf("Danger Will Robinson! Failure in attempt to shoot a Splitter!\n");}/****************************** seeker::TheCoastIsClear ******************************* Dealing with seekers that spawn other seekers is tricky. We have to make sure that thespot we wish to place the new seekers in is clear, i.e. we can't put them in a spot thatsomething else already occupies. This function is used to check to see if a given areaof real estate is clear and available for new seekers to be born into. If it is, thenit installs the birth anim as an object that fills up the whole space.*****************************************************************************************/bool seeker::TheCoastIsClear (dude *splitter, int32 direction, anim_source *new_anim, int32 orig_x, int32 orig_y, int32 offset_x, int32 offset_y, int32 new_col_detect_x, int32 new_col_detect_y){ solid_object *obstruction; splitter->blocker->col_detect_x = new_col_detect_x; splitter->blocker->col_detect_y = new_col_detect_y; offset_x = offset_x << 16; offset_y = offset_y << 16; splitter->special_anim.current_frame_ccb->ccb_XPos = orig_x + offset_x; splitter->special_anim.current_frame_ccb->ccb_YPos = orig_y + offset_y; obstruction = population.DetectCollision(splitter->blocker,FALSE); if ((obstruction == (solid_object *) NULL) || (obstruction->object_type == DEATH_SCENE)) { /* get rid of the stasis anim */ population.EliminateObject(splitter->blocker); splitter->special_anim.ShutdownForRestart(); splitter->special_anim.InitializeAnim (new_anim, STANDARD_FRAME_RATE); splitter->special_anim.Restart(); splitter->special_anim.current_frame_ccb->ccb_XPos = orig_x + offset_x; splitter->special_anim.current_frame_ccb->ccb_YPos = orig_y + offset_y; population.AddToList(splitter->special_anim.current_frame_ccb, SPLIT_SCENE, new_col_detect_x, new_col_detect_y); splitter->blocker = population.FindPointerIntoList (splitter->special_anim.current_frame_ccb); splitter->health = SPLITTING; splitter->special = direction; return(TRUE); } return(FALSE);}/**************************** seeker::FinalSeparation ******************************** The birth of a pair of spawning seekers has 2 parts. First, the birth animation isstarted in the space where the original seeker was shot. Then, after the birth animhas run its course, 2 new seekers are inserted at the correct coordinates and thebirth animation is removed. This function handles this second part of the process.*****************************************************************************************/void seeker::FinalSeparation (dude *mom, int32 new_type, int32 offset_x_a, int32 offset_y_a,int32 offset_x_b,int32 offset_y_b){ dude *dude_a; dude *dude_b; int32 breed; int32 special; breed = mom->breed; special = mom->special; dude_a = CreateSeeker(new_type, mom->home_row, mom->home_column,mom->home_offset,TRUE); dude_a->walk_anim[dude_a->direction].current_frame_ccb->ccb_XPos = mom->special_anim.current_frame_ccb->ccb_XPos + (offset_x_a << 16); dude_a->walk_anim[dude_a->direction].current_frame_ccb->ccb_YPos = mom->special_anim.current_frame_ccb->ccb_YPos + (offset_y_a << 16); population.FixPositionOnList(dude_a->solids_entry); dude_b = CreateSeeker(new_type, mom->home_row, mom->home_column,mom->home_offset,TRUE); dude_b->walk_anim[dude_b->direction].current_frame_ccb->ccb_XPos = mom->special_anim.current_frame_ccb->ccb_XPos + (offset_x_b << 16); dude_b->walk_anim[dude_b->direction].current_frame_ccb->ccb_YPos = mom->special_anim.current_frame_ccb->ccb_YPos + (offset_y_b << 16); population.FixPositionOnList(dude_b->solids_entry); /* get rid of the splitting anim */ population.EliminateObject(mom->blocker); /* make sure there really was nothing in their way */ if ((Obstructed(dude_a,FALSE)) && (dude_a->blocker->object_type != DEATH_SCENE)) { printf("Type %ld splitter's A child was born obstructed after type %ld birth.\n", mom->breed, mom->special); if ((dude_a->blocker->object_type >= FIRST_BOULDER) && (dude_a->blocker->object_type <= LAST_BOULDER)) printf("It was a rock.\n"); } if ((Obstructed(dude_b,FALSE)) && (dude_b->blocker->object_type != DEATH_SCENE)) { printf("Type %ld splitter's B child was born obstructed after type %ld birth.\n", mom->breed, mom->special); if ((dude_b->blocker->object_type >= FIRST_BOULDER) && (dude_b->blocker->object_type <= LAST_BOULDER)) printf("It was a rock.\n"); } /* change health so that the caller will know to destroy the original splitter */ mom->health = DEAD;}/****************************** seeker::NurgeSplitter ********************************** When a seeker that spawns 2 smaller seekers when shot is shot, this function is calledto deal with the matter of getting the split going. The verb we use to describe this is"to nurge." When a nurgeable seeker is shot, it will try to nurge its spawn out from its originallocation in any of 5 different ways. It first tries a centralized nurge, but if thereare objects in the way that prohibit this, we try nurging in all of the 4 main compasspoints, hoping to find an area that is clear. If the splitter is completely surrounded,then we simply stay put and advance the frame on our stasis anim, which shows usattempting to nurge but not actually succeeding.*****************************************************************************************/void seeker::NurgeSplitter (dude *splitter){ int32 old_x,old_y; int32 old_col_detect_x,old_col_detect_y; old_x = splitter->blocker->cel->ccb_XPos; old_y = splitter->blocker->cel->ccb_YPos; old_col_detect_x = splitter->blocker->col_detect_x; old_col_detect_y = splitter->blocker->col_detect_y; if (splitter->breed == MEANY) { if (TheCoastIsClear (splitter, NO_DIRECTION, &meany_split,old_x,old_y, 0, 0, (PYRAMID_COL_DETECT_X * 2) + 3, PYRAMID_COL_DETECT_Y)) { // printf("nurging MEANY in DEFAULT direction.\n"); return; } if (TheCoastIsClear (splitter, WEST, &meany_split_w, old_x, old_y, -9, 0, (PYRAMID_COL_DETECT_X * 2) + 3, PYRAMID_COL_DETECT_Y)) { // printf("nurging MEANY in WEST direction.\n"); return; } if (TheCoastIsClear (splitter, EAST, &meany_split_e, old_x, old_y, 9, 0, (PYRAMID_COL_DETECT_X * 2) + 3, PYRAMID_COL_DETECT_Y)) { // printf("nurging MEANY in EAST direction.\n"); return; } if (TheCoastIsClear (splitter, NORTH, &meany_split_n, old_x, old_y, 0, -6, PYRAMID_COL_DETECT_X, (PYRAMID_COL_DETECT_Y * 2) + 4)) { // printf("nurging MEANY in NORTH direction.\n"); return; } if (TheCoastIsClear (splitter, SOUTH, &meany_split_s, old_x, old_y, 0, 6, PYRAMID_COL_DETECT_X, (PYRAMID_COL_DETECT_Y * 2) + 3)) { // printf("nurging MEANY in SOUTH direction.\n"); return; } } if (splitter->breed == NASTY) { if (TheCoastIsClear (splitter, NO_DIRECTION, &nasty_split,old_x,old_y, 0,0, (PYRAMID_COL_DETECT_X * 2) - 1, PYRAMID_COL_DETECT_Y)) { // printf("nurging NASTY in DEFAULT direction.\n"); return; } if (TheCoastIsClear (splitter, WEST, &nasty_split_w, old_x, old_y, -7, 0, (PYRAMID_COL_DETECT_X * 2) - 1, PYRAMID_COL_DETECT_Y)) { // printf("nurging NASTY in WEST direction.\n"); return; } if (TheCoastIsClear (splitter, EAST, &nasty_split_e, old_x, old_y, 7, 0, (PYRAMID_COL_DETECT_X * 2) - 1, PYRAMID_COL_DETECT_Y)) { // printf("nurging NASTY in EAST direction.\n"); return; } if (TheCoastIsClear (splitter, NORTH, &nasty_split_n, old_x, old_y, 0, -5, PYRAMID_COL_DETECT_X, (PYRAMID_COL_DETECT_Y * 2) + 2)) { // printf("nurging NASTY in NORTH direction.\n"); return; } if (TheCoastIsClear (splitter, SOUTH, &nasty_split_s, old_x, old_y, 0, 5, PYRAMID_COL_DETECT_X, (PYRAMID_COL_DETECT_Y * 2) + 2)) { // printf("nurging NASTY in SOUTH direction.\n"); return; } } /* If we haven't had room to split off in any direction, then wait until next time */ splitter->special_anim.current_frame_ccb->ccb_XPos = old_x; splitter->special_anim.current_frame_ccb->ccb_YPos = old_y; splitter->blocker->col_detect_x = old_col_detect_x; splitter->blocker->col_detect_y = old_col_detect_y; splitter->special_anim.AdvanceFrame();}/**************************** seeker::MaintainSplitter ******************************** This function is used to babysit a splitter that is in the process of nurging. If thenurge is only partly complete, it just advances the frame; if the nurge is complete,then it calls the routine to complete the birth process as is appropriate for thedirection of the nurge.*****************************************************************************************/void seeker::MaintainSplitter (dude *splitter){ if ((splitter->special_anim.AnimComplete())) { if (splitter->breed == MEANY) { if ((splitter->special == NO_DIRECTION) || (splitter->special == WEST) || (splitter->special == EAST)) FinalSeparation (splitter, NASTY, -9, 0, 9, 0); if ((splitter->special == NORTH) || (splitter->special == SOUTH)) FinalSeparation (splitter, NASTY, 0, 8, 0, -4); } if (splitter->breed == NASTY) { if ((splitter->special == NO_DIRECTION) || (splitter->special == WEST) || (splitter->special == EAST)) FinalSeparation (splitter, GRUMPY, -7, 0, 7, 0); if ((splitter->special == NORTH) || (splitter->special == SOUTH)) FinalSeparation (splitter, GRUMPY, 0, 6, 0, -4); } } else splitter->special_anim.AdvanceFrame();}/************************ seeker::CheckForSeekerCollisions **************************** This function takes a solid object and goes through the seeker list to see if thereare any collisions between the specified solid object and any of the seekers on the list. This function is not currently in use.*****************************************************************************************/solid_object* seeker::CheckForSeekerCollisions (register solid_object *target){ register int32 target_center_x,target_center_y; register dude *traversal_ptr; traversal_ptr = seeker_list; target_center_x = FIND_CENTER_X (target->cel); target_center_y = FIND_CENTER_Y (target->cel); while (traversal_ptr != (dude *) NULL) { if ( ((ABS(FIND_CENTER_X (traversal_ptr->solids_entry->cel) - target_center_x)) <= traversal_ptr->solids_entry->col_detect_x + target->col_detect_x) && ((ABS(FIND_CENTER_Y (traversal_ptr->solids_entry->cel) - target_center_y)) <= traversal_ptr->solids_entry->col_detect_y + target->col_detect_y) ) { if (traversal_ptr->solids_entry != target) return(traversal_ptr->solids_entry); } traversal_ptr = traversal_ptr->next; } return((solid_object *) NULL);}/************************* seeker::ShutdownForRestart ********************************* When a game ends, the player will either wish to quit or play again. In either case,this function should be called to surrender memory that was dynamically allocated duringthe game. Needless to say, it is particularly important that this function be calledafter every game; otherwise the memory that was used cannot be re-allocated.*****************************************************************************************/void seeker::ShutdownForRestart(void){ register dude *target, *vanguard_ptr; int32 i; target = seeker_list; while (target != (dude *) NULL) { vanguard_ptr = target->next;printf("["); for (i = 0; i < 8; i++) target->walk_anim[i].ShutdownForRestart(); target->stumbling.ShutdownForRestart(); target->special_anim.ShutdownForRestart();switch(target->breed){case YELLOW_SEEKER: printf("Y"); break;case LTBLUE_SEEKER: printf("B"); break;case PINK_SEEKER: printf("P"); break;case LIME_SEEKER: printf("L"); break;case DORMANT_CHAMELEON: printf("C"); break;case WAKING_CHAMELEON: printf("c"); break;case ACTIVE_CHAMELEON: printf("c"); break;case ZOMBIE: printf("Z"); break;case LURKER: printf("K"); break;case MEANY: printf("M"); break;case NASTY: printf("N"); break;case GRUMPY: printf("G"); break;case JUGGERNAUT: printf("J"); break;case PSYCHO: printf("S"); break;case DORMANT_REDCOAT: printf("R"); break;case WAKING_REDCOAT: printf("r"); break;case ACTIVE_REDCOAT: printf("r"); break;case DORMANT_BUMMER: printf("U"); break;case WAKING_BUMMER: printf("u"); break;case ACTIVE_BUMMER: printf("u"); break;} delete(target);printf("]"); target = vanguard_ptr; }printf(" ");}/********************************* seeker::Loaded ************************************* The purpose of this function is to inform the caller about the artwork status of therequested seeker type. This function returns TRUE if the artwork for the seeker is loaded,and FALSE if it isn't.*****************************************************************************************/bool seeker::Loaded(int32 seeker_type){ switch (seeker_type) { case YELLOW_SEEKER: if (yellow_piece_cel != NULL) return(TRUE); else return(FALSE); case LTBLUE_SEEKER: if (ltblue_piece_cel != NULL) return(TRUE); else return(FALSE); case PINK_SEEKER: if (pink_piece_cel != NULL) return(TRUE); else return(FALSE); case LIME_SEEKER: if (lime_piece_cel != NULL) return(TRUE); else return(FALSE); case LURKER: if (lurker_piece_cel != NULL) return(TRUE); else return(FALSE); case ZOMBIE: if (zombie_birth.anim_pointer != NULL) return(TRUE); else return(FALSE); case JUGGERNAUT: if (jugger_pit_death.anim_pointer != NULL) return(TRUE); else return(FALSE); case PSYCHO: if (psycho_pit_death.anim_pointer != NULL) return(TRUE); else return(FALSE); case MEANY: if (meany_walk_e_w_n_s.anim_pointer != NULL) return(TRUE); else return(FALSE); case NASTY: if (nasty_walk_e_w_n_s.anim_pointer != NULL) return(TRUE); else return(FALSE); case GRUMPY: if (grumpy_walk_e_w_n_s.anim_pointer != NULL) return(TRUE); else return(FALSE); } return(FALSE);}/************************* seeker::CheckForCorruptedGrumpies *************************** The purpose of this routine is to run through the seeker list and clear out the blockerpointer for any solid that has been eliminated. In most cases this is not necessarybecause most objects are eliminated prior to the AnimateSeekers function and by thetime that function is reached, a seeker can correct for a destroyed object on its own.The problem (and boy was this a bitch to debug) comes when a split scene is destroyedin the midst of the AnimateSeekers routine, and new seekers added as part of the splittingprocess don't find out about it until after the trash has been emptied. This functionserves to solve this problem. These lines here were the ones that allowed me to determine that a seeker's blockerpointer had become corrupted, from which point I was able to trace back to the problem. if ((target->blocker != (solid_object *) NULL) && ((target->blocker->object_type >= DUDEMEYER) || (target->blocker->object_type <= YELLOW_PYRAMID))) printf("Seeker of type %ld has been corrupted.\n",target->breed);*****************************************************************************************/void seeker::CheckForCorruptedGrumpies(){ dude *target; target = seeker_list; while (target != (dude *) NULL) { if ((target->blocker != (solid_object *) NULL) && (target->blocker->cel == (CCB *) NULL)) target->blocker = (solid_object *) NULL; target = target->next; }}/****************************** seeker::ResetSeekers *********************************** This function sends ALL seekers on the seeker list back to their home bases. The onlyuse for this is for restarting a game, if you decide to give players more than one life.*****************************************************************************************/void seeker::ResetSeekers(){ dude *target; target = seeker_list; while (target != (dude *) NULL) { if ((target->breed != DORMANT_CHAMELEON) && (target->breed != DORMANT_REDCOAT) && (target->breed != DORMANT_BUMMER)) SendHome(target); target = target->next; }}/****************************** seeker::CountSeekers *********************************** This function returns the total number of seekers currently in existence on the level.*****************************************************************************************/int32 seeker::CountSeekers(){ dude *target; int32 total_seekers; total_seekers = 0; target = seeker_list; while (target != (dude *) NULL) { total_seekers++; target = target->next; } return(total_seekers);}/***************************** seeker::ScottyEnergize ********************************** This function is manages the beaming in of a seeker on a seeker generator tile.*****************************************************************************************/void seeker::ScottyEnergize(dude *target){ /*************************************************************************************/ /***** STAGE ONE: The seeker is waiting for the transporter pad to be clear. *********/ /*************************************************************************************/ if (target->health == MATERIALIZING_1) { if ((target->blocker != (solid_object *) NULL) && (target->blocker->object_type != GREEN_PYRAMID)) { if ( ((ABS((FIND_CENTER_X (target->last_hazard)) - (FIND_CENTER_X (target->blocker->cel)))) <= PYRAMID_COL_DETECT_X + target->blocker->col_detect_x) && ((ABS((FIND_CENTER_Y (target->last_hazard)) - (FIND_CENTER_Y (target->blocker->cel)))) <= PYRAMID_COL_DETECT_Y + target->blocker->col_detect_y) ) return; } target->beamin.current_frame_ccb->ccb_XPos = target->last_hazard->ccb_XPos; target->beamin.current_frame_ccb->ccb_YPos = target->last_hazard->ccb_YPos; population.FixPositionOnList(target->solids_entry); if (Obstructed(target,FALSE)) { target->beamin.current_frame_ccb->ccb_XPos=0xFFF0000; target->beamin.current_frame_ccb->ccb_YPos=0xFFF0000; population.FixPositionOnList(target->solids_entry); } else { target->health = MATERIALIZING_2; if (ObjectVisible(target->last_hazard)) PlaySoundEffect(GENERATOR_SOUND); } return; } /*************************************************************************************/ /***** STAGE TWO: The beam in process is underway, but the seeker ain't visible yet. */ /*************************************************************************************/ if (target->health == MATERIALIZING_2) { target->beamin.AdvanceFrame(); if (target->beamin.AnimComplete()) { target->direction = NORTH; target->walk_anim[target->direction].Restart(); if (target->breed == MEANY) { while(!(target->walk_anim[target->direction].AnimOnGivenFrame(9))) target->walk_anim[target->direction].AdvanceFrame(); } if (target->breed == NASTY) { while(!(target->walk_anim[target->direction].AnimOnGivenFrame(7))) target->walk_anim[target->direction].AdvanceFrame(); } morgue.CreateDeathScene (&beam_in_part2,STANDARD_FRAME_RATE, target->beamin.current_frame_ccb->ccb_XPos, target->beamin.current_frame_ccb->ccb_YPos,0,0,0); target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->last_hazard->ccb_XPos; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->last_hazard->ccb_YPos; target->current_row = target->home_row; target->current_column = target->home_column; if ((target->breed == LURKER) || (target->breed == PSYCHO) || (target->breed == LIME_SEEKER)) { target->special_anim.Restart(); target->solids_entry->cel = target->special_anim.current_frame_ccb; target->special_anim.current_frame_ccb->ccb_XPos = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; target->special_anim.current_frame_ccb->ccb_YPos = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; } /* since SendHome randomizes 'em, re-cue walk anims. */ switch (target->breed) { case MEANY: while(!(target->walk_anim[target->direction].AnimOnGivenFrame(9))) target->walk_anim[target->direction].AdvanceFrame(); break; case NASTY: while(!(target->walk_anim[target->direction].AnimOnGivenFrame(7))) target->walk_anim[target->direction].AdvanceFrame(); break; default: while(!(target->walk_anim[target->direction].AnimCued())) target->walk_anim[target->direction].AdvanceFrame(); break; } target->health = MATERIALIZING_3; } return; } /*************************************************************************************/ /***** STAGE THREE: The seeker has arrived on the pad, but is held in place until */ /* the materialization effects are complete. */ /*************************************************************************************/ if (target->health == MATERIALIZING_3) { if (target->breed == PSYCHO) target->special_anim.AdvanceFrame(); if (Obstructed(target,FALSE)) return; if ((target->breed == LURKER) || (target->breed == PSYCHO) || (target->breed == LIME_SEEKER)) { if (target->breed == LURKER) target->special = 1; target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->last_hazard->ccb_XPos; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->last_hazard->ccb_YPos; } target->health = NOT_DEAD; target->last_hazard = (CCB *) NULL; return; }}/******************************* seeker::StillMoving *********************************** This function is used when a player has died. Its purpose is to follow through on thewalking animations of all seekers until they all get to the point at which they arestanding plain and upright in pyramid shapes instead of in twisted and contorted movingpositions. As long as a seeker is still moving, we return TRUE.*****************************************************************************************/bool seeker::StillMoving(){ dude *target; bool return_value; int32 x,y; return_value = FALSE; target = seeker_list; while (target != (dude *) NULL) { if ((target->health == MATERIALIZING_2) || (target->health == MATERIALIZING_3)) { ScottyEnergize(target); if (target->health == MATERIALIZING_2) return_value = TRUE; } if (target->health == NOT_DEAD) { switch (target->breed) { case MEANY: if(!(target->walk_anim[target->direction].AnimOnGivenFrame(9))) { target->walk_anim[target->direction].AdvanceFrame(); return_value = TRUE; } break; case NASTY: if(!(target->walk_anim[target->direction].AnimOnGivenFrame(7))) { target->walk_anim[target->direction].AdvanceFrame(); return_value = TRUE; } break; case PSYCHO: if (!(target->walk_anim[target->direction].AnimCued())) { target->walk_anim[target->direction].AdvanceFrame(); return_value = TRUE; } else { if (target->special == FALSE) { target->solids_entry->cel = target->special_anim.current_frame_ccb; target->special_anim.current_frame_ccb->ccb_XPos = target->walk_anim[target->direction] .current_frame_ccb->ccb_XPos; target->special_anim.current_frame_ccb->ccb_YPos = target->walk_anim[target->direction] .current_frame_ccb->ccb_YPos; target->special = TRUE; return_value = TRUE; } else target->special_anim.AdvanceFrame(); } break; case WAKING_CHAMELEON: case WAKING_REDCOAT: case WAKING_BUMMER: return_value = TRUE; MaintainChameleon (target); break; case ACTIVE_REDCOAT: case LURKER: x = target->solids_entry->cel->ccb_XPos; y = target->solids_entry->cel->ccb_YPos; memcpy(target->solids_entry->cel,lurker_piece_cel,sizeof(CCB)); target->solids_entry->cel->ccb_XPos = x; target->solids_entry->cel->ccb_YPos = y; break; case ACTIVE_CHAMELEON: case LIME_SEEKER: x = target->solids_entry->cel->ccb_XPos; y = target->solids_entry->cel->ccb_YPos; memcpy(target->solids_entry->cel,lime_piece_cel,sizeof(CCB)); target->solids_entry->cel->ccb_XPos = x; target->solids_entry->cel->ccb_YPos = y; break; case ZOMBIE: if (target->special == 0) { ReviveZombie (target); return_value = TRUE; break; } if (target->special < 0) break; default: if (!(target->walk_anim[target->direction].AnimCued())) { target->walk_anim[target->direction].AdvanceFrame(); return_value = TRUE; } break; } } target = target->next; } return(return_value);}/************************* seeker::MoveBoredSeekersAround ****************************** This function is used by the screen saver. It makes all seekers on the seeker listmill aimlessly around.*****************************************************************************************/void seeker::MoveBoredSeekersAround(){ dude *target; bool moved; int32 old_x,old_y; int32 new_direction; target = seeker_list; while (target != (dude *) NULL) { old_x = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; old_y = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; moved = FALSE; if ((target->breed == LURKER) && (target->special < 0)) { target->special++; target->special_anim.AdvanceFrame(); if ((target->special == 0) && (!(target->special_anim.AnimCued()))) target->special--; if (target->special == 0) { target->solids_entry->cel = target->walk_anim[target->direction].current_frame_ccb; target->walk_anim[target->direction].current_frame_ccb->ccb_XPos = target->special_anim.current_frame_ccb->ccb_XPos; target->walk_anim[target->direction].current_frame_ccb->ccb_YPos = target->special_anim.current_frame_ccb->ccb_YPos; } } else { /* some seekers need to be stopped for a frame or 2 to make their movement */ /* animations look right. */ if ((target->breed == YELLOW_SEEKER) && (target->walk_anim[target->direction].AnimComplete())) moved = TRUE; if ((target->breed == MEANY) && ((target->walk_anim[target->direction].AnimComplete()) || (target->walk_anim[target->direction].AnimCued()))) moved = TRUE; if ((target->breed == NASTY) && (target->walk_anim[target->direction].AnimComplete())) moved = TRUE; /* now, if we haven't halted the seeker, move it according to its smarts. */ if (!(moved)) { moved = TRUE; if ((GravitateTowardsPoint (target->walk_anim[target->direction].current_frame_ccb, (target->horz_speed >> 16),target->home_row,target->home_column))) { target->home_row = RandomNumber(-50,370); target->home_column = RandomNumber(-50,290); } if (Obstructed(target,FALSE)) moved = AvoidObstruction(target,old_x,old_y, RandomNumber(0,target->horz_speed), RandomNumber(0,target->vert_speed)); } if (moved) { target->immobile_counter = 0; new_direction = DetermineDirection(target,old_x,old_y); if (new_direction != target->direction) ChangeDirection(target, new_direction); target->walk_anim[target->direction].AdvanceFrame(); population.FixPositionOnList(target->solids_entry); if (target->breed == LURKER) { target->special++; if ((target->special >= LURKER_AWAKE_PHASE) && (target->walk_anim[target->direction].AnimCued())) { target->special = (-1) * LURKER_SLEEP_PHASE; target->solids_entry->cel = target->special_anim.current_frame_ccb; target->special_anim.current_frame_ccb->ccb_XPos = target->walk_anim[target->direction].current_frame_ccb->ccb_XPos; target->special_anim.current_frame_ccb->ccb_YPos = target->walk_anim[target->direction].current_frame_ccb->ccb_YPos; } } } else { /* Even though we aren't moving, keeping playing animation while until */ /* re-cued so that it doesn't stop on a frame that looks dumb. On the */ /* other hand, some seekers never really stop, so keep animating them. */ switch (target->breed) { case PSYCHO: case LURKER: case LIME_SEEKER: target->walk_anim[target->direction].AdvanceFrame(); break; case MEANY: if (!(target->walk_anim[target->direction].AnimOnGivenFrame(9))) target->walk_anim[target->direction].AdvanceFrame(); break; case NASTY: if (!(target->walk_anim[target->direction].AnimOnGivenFrame(7))) target->walk_anim[target->direction].AdvanceFrame(); break; default: if (!(target->walk_anim[target->direction].AnimCued())) target->walk_anim[target->direction].AdvanceFrame(); break; } } } target = target->next; }}/**************************** seeker::ShutdownForExit ********************************* This function deallocates memory that was reserved for storage of artwork elementsthat are used repeatedly over a sequence of many games. This function should be calledwhen (but only when) the program is about to be shutdown for good.*****************************************************************************************/void seeker::ShutdownForExit(void){ if (yellow_piece_cel != NULL) UnloadCel(yellow_piece_cel); yellow_walk_e.ShutdownForExit(); yellow_walk_w.ShutdownForExit(); yellow_walk_n.ShutdownForExit(); yellow_walk_s.ShutdownForExit(); yellow_walk_se.ShutdownForExit(); yellow_walk_sw.ShutdownForExit(); yellow_walk_ne.ShutdownForExit(); yellow_walk_nw.ShutdownForExit(); yellow_pit_death.ShutdownForExit(); yellow_lava_death.ShutdownForExit(); yellow_death.ShutdownForExit(); if (ltblue_piece_cel != NULL) UnloadCel(ltblue_piece_cel); ltblue_walk_e.ShutdownForExit(); ltblue_walk_w.ShutdownForExit(); ltblue_walk_n.ShutdownForExit(); ltblue_walk_s.ShutdownForExit(); ltblue_walk_se.ShutdownForExit(); ltblue_walk_sw.ShutdownForExit(); ltblue_walk_ne.ShutdownForExit(); ltblue_walk_nw.ShutdownForExit(); ltblue_pit_death.ShutdownForExit(); ltblue_lava_death.ShutdownForExit(); ltblue_death.ShutdownForExit(); if (pink_piece_cel != NULL) UnloadCel(pink_piece_cel); pink_walk_e.ShutdownForExit(); pink_walk_w.ShutdownForExit(); pink_walk_n.ShutdownForExit(); pink_walk_s.ShutdownForExit(); pink_walk_se.ShutdownForExit(); pink_walk_sw.ShutdownForExit(); pink_walk_ne.ShutdownForExit(); pink_walk_nw.ShutdownForExit(); pink_pit_death.ShutdownForExit(); pink_lava_death.ShutdownForExit(); pink_death.ShutdownForExit(); if (lime_piece_cel != NULL) UnloadCel(lime_piece_cel); lime_pit_death.ShutdownForExit(); lime_lava_death.ShutdownForExit(); lime_still.ShutdownForExit(); lime_walk_e.ShutdownForExit(); lime_walk_w.ShutdownForExit(); lime_walk_n.ShutdownForExit(); lime_walk_s.ShutdownForExit(); lime_walk_se.ShutdownForExit(); lime_walk_sw.ShutdownForExit(); lime_walk_ne.ShutdownForExit(); lime_walk_nw.ShutdownForExit(); lime_death_e.ShutdownForExit(); lime_death_w.ShutdownForExit(); lime_death_s.ShutdownForExit(); lime_death_n.ShutdownForExit(); cham_wakeup_anim.ShutdownForExit(); cham_death_e.ShutdownForExit(); cham_death_w.ShutdownForExit(); cham_death_n.ShutdownForExit(); cham_death_s.ShutdownForExit(); redcoat_wakeup_anim.ShutdownForExit(); redcoat_death_e.ShutdownForExit(); redcoat_death_w.ShutdownForExit(); redcoat_death_n.ShutdownForExit(); redcoat_death_s.ShutdownForExit(); bummer_wakeup_anim.ShutdownForExit(); bummer_death.ShutdownForExit(); zombie_death.ShutdownForExit(); zombie_birth.ShutdownForExit(); zombie_shrapnel.ShutdownForExit(); zombie1_walk_e.ShutdownForExit(); zombie1_walk_n.ShutdownForExit(); zombie1_walk_w.ShutdownForExit(); zombie1_walk_s.ShutdownForExit(); zombie1_walk_sw.ShutdownForExit(); zombie1_walk_se.ShutdownForExit(); zombie1_walk_nw.ShutdownForExit(); zombie1_walk_ne.ShutdownForExit(); zombie2_walk_e.ShutdownForExit(); zombie2_walk_n.ShutdownForExit(); zombie2_walk_w.ShutdownForExit(); zombie2_walk_s.ShutdownForExit(); zombie2_walk_sw.ShutdownForExit(); zombie2_walk_se.ShutdownForExit(); zombie2_walk_nw.ShutdownForExit(); zombie2_walk_ne.ShutdownForExit(); zombie3_walk_e.ShutdownForExit(); zombie3_walk_n.ShutdownForExit(); zombie3_walk_w.ShutdownForExit(); zombie3_walk_s.ShutdownForExit(); zombie3_walk_sw.ShutdownForExit(); zombie3_walk_se.ShutdownForExit(); zombie3_walk_nw.ShutdownForExit(); zombie3_walk_ne.ShutdownForExit(); zombie1pit_death.ShutdownForExit(); zombie2pit_death.ShutdownForExit(); zombie3pit_death.ShutdownForExit(); zombie1lava_death.ShutdownForExit(); zombie2lava_death.ShutdownForExit(); zombie3lava_death.ShutdownForExit(); if (lurker_piece_cel != NULL) UnloadCel(lurker_piece_cel); lurker_walk_e.ShutdownForExit(); lurker_walk_w.ShutdownForExit(); lurker_walk_n.ShutdownForExit(); lurker_walk_s.ShutdownForExit(); lurker_walk_se.ShutdownForExit(); lurker_walk_sw.ShutdownForExit(); lurker_walk_ne.ShutdownForExit(); lurker_walk_nw.ShutdownForExit(); lurker_wait.ShutdownForExit(); lurker_pit_death.ShutdownForExit(); lurker_lava_death.ShutdownForExit(); lurker_death_e.ShutdownForExit(); lurker_death_w.ShutdownForExit(); lurker_death_s.ShutdownForExit(); lurker_death_n.ShutdownForExit(); meany_walk_e_w_n_s.ShutdownForExit(); meany_walk_se_nw.ShutdownForExit(); meany_walk_ne_sw.ShutdownForExit(); meany_pit_death.ShutdownForExit(); meany_lava_death.ShutdownForExit(); meany_split.ShutdownForExit(); meany_stasis.ShutdownForExit(); meany_split_e.ShutdownForExit(); meany_split_w.ShutdownForExit(); meany_split_n.ShutdownForExit(); meany_split_s.ShutdownForExit(); nasty_walk_e_w_n_s.ShutdownForExit(); nasty_walk_se_nw.ShutdownForExit(); nasty_walk_ne_sw.ShutdownForExit(); nasty_pit_death.ShutdownForExit(); nasty_lava_death.ShutdownForExit(); nasty_split.ShutdownForExit(); nasty_stasis.ShutdownForExit(); nasty_split_e.ShutdownForExit(); nasty_split_w.ShutdownForExit(); nasty_split_n.ShutdownForExit(); nasty_split_s.ShutdownForExit(); grumpy_walk_e_w_n_s.ShutdownForExit(); grumpy_walk_se_nw.ShutdownForExit(); grumpy_walk_ne_sw.ShutdownForExit(); grumpy_pit_death.ShutdownForExit(); grumpy_lava_death.ShutdownForExit(); grumpy_death.ShutdownForExit(); jugger_walk_e.ShutdownForExit(); jugger_walk_w.ShutdownForExit(); jugger_walk_n.ShutdownForExit(); jugger_walk_s.ShutdownForExit(); jugger_walk_se.ShutdownForExit(); jugger_walk_sw.ShutdownForExit(); jugger_walk_ne.ShutdownForExit(); jugger_walk_nw.ShutdownForExit(); jugger_pit_death.ShutdownForExit(); jugger_lava_death.ShutdownForExit(); jugger_death.ShutdownForExit(); psycho_walk_e.ShutdownForExit(); psycho_walk_w.ShutdownForExit(); psycho_walk_n.ShutdownForExit(); psycho_walk_s.ShutdownForExit(); psycho_walk_se.ShutdownForExit(); psycho_walk_sw.ShutdownForExit(); psycho_walk_ne.ShutdownForExit(); psycho_walk_nw.ShutdownForExit(); psycho_pit_death.ShutdownForExit(); psycho_lava_death.ShutdownForExit(); psycho_unmoving.ShutdownForExit(); psycho_death[0].ShutdownForExit(); psycho_death[1].ShutdownForExit(); psycho_death[2].ShutdownForExit(); beam_in_part1.ShutdownForExit(); beam_in_part2.ShutdownForExit();}/************************** seeker::ShutdownUnusedArtwork ****************************** This function examines all of the art elements used by this class and gets rid of anythat are not currently needed, thus freeing up the memory this art was consuming for moreworthwhile causes. The way in which we know whether or not a piece of art is needed isby examining the values in the global art usage table (g_art_usage). This table is filledout by the function LoadLevel as the level parameters are parsed. Anything that isn'tset to TRUE in this table will not be needed during this level and can therefore safelybe discarded.*****************************************************************************************/void seeker::ShutdownUnusedArtwork(void){ if ((yellow_piece_cel != NULL) && (g_art_usage[YELLOW_SEEKER] == FALSE)) { UnloadCel(yellow_piece_cel); yellow_piece_cel = (CCB *) NULL; yellow_walk_e.ShutdownForExit(); yellow_walk_w.ShutdownForExit(); yellow_walk_n.ShutdownForExit(); yellow_walk_s.ShutdownForExit(); yellow_walk_se.ShutdownForExit(); yellow_walk_sw.ShutdownForExit(); yellow_walk_ne.ShutdownForExit(); yellow_walk_nw.ShutdownForExit(); yellow_pit_death.ShutdownForExit(); yellow_lava_death.ShutdownForExit(); yellow_death.ShutdownForExit(); } if ((ltblue_piece_cel != NULL) && (g_art_usage[LTBLUE_SEEKER] == FALSE) && (g_art_usage[DORMANT_BUMMER] == FALSE)) { UnloadCel(ltblue_piece_cel); ltblue_piece_cel = (CCB *) NULL; ltblue_walk_e.ShutdownForExit(); ltblue_walk_w.ShutdownForExit(); ltblue_walk_n.ShutdownForExit(); ltblue_walk_s.ShutdownForExit(); ltblue_walk_se.ShutdownForExit(); ltblue_walk_sw.ShutdownForExit(); ltblue_walk_ne.ShutdownForExit(); ltblue_walk_nw.ShutdownForExit(); ltblue_pit_death.ShutdownForExit(); ltblue_lava_death.ShutdownForExit(); ltblue_death.ShutdownForExit(); } if ((pink_piece_cel != NULL) && (g_art_usage[PINK_SEEKER] == FALSE)) { UnloadCel(pink_piece_cel); pink_piece_cel = (CCB *) NULL; pink_walk_e.ShutdownForExit(); pink_walk_w.ShutdownForExit(); pink_walk_n.ShutdownForExit(); pink_walk_s.ShutdownForExit(); pink_walk_se.ShutdownForExit(); pink_walk_sw.ShutdownForExit(); pink_walk_ne.ShutdownForExit(); pink_walk_nw.ShutdownForExit(); pink_pit_death.ShutdownForExit(); pink_lava_death.ShutdownForExit(); pink_death.ShutdownForExit(); } if ((lime_piece_cel != NULL) && (g_art_usage[LIME_SEEKER] == FALSE) && (g_art_usage[DORMANT_CHAMELEON] == FALSE)) { UnloadCel(lime_piece_cel); lime_piece_cel = (CCB *) NULL; lime_pit_death.ShutdownForExit(); lime_lava_death.ShutdownForExit(); lime_still.ShutdownForExit(); lime_walk_e.ShutdownForExit(); lime_walk_w.ShutdownForExit(); lime_walk_n.ShutdownForExit(); lime_walk_s.ShutdownForExit(); lime_walk_se.ShutdownForExit(); lime_walk_sw.ShutdownForExit(); lime_walk_ne.ShutdownForExit(); lime_walk_nw.ShutdownForExit(); lime_death_e.ShutdownForExit(); lime_death_w.ShutdownForExit(); lime_death_s.ShutdownForExit(); lime_death_n.ShutdownForExit(); } if ((cham_wakeup_anim.anim_pointer != NULL) && (g_art_usage[DORMANT_CHAMELEON] == FALSE)) { cham_wakeup_anim.ShutdownForExit(); cham_death_e.ShutdownForExit(); cham_death_w.ShutdownForExit(); cham_death_n.ShutdownForExit(); cham_death_s.ShutdownForExit(); } if ((redcoat_wakeup_anim.anim_pointer != NULL) && (g_art_usage[DORMANT_REDCOAT] == FALSE)) { redcoat_wakeup_anim.ShutdownForExit(); redcoat_death_e.ShutdownForExit(); redcoat_death_w.ShutdownForExit(); redcoat_death_n.ShutdownForExit(); redcoat_death_s.ShutdownForExit(); } if ((bummer_wakeup_anim.anim_pointer != NULL) && (g_art_usage[DORMANT_BUMMER] == FALSE)) { bummer_wakeup_anim.ShutdownForExit(); bummer_death.ShutdownForExit(); } if ((zombie_birth.anim_pointer != NULL) && (g_art_usage[ZOMBIE] == FALSE)) { zombie_birth.ShutdownForExit(); zombie_death.ShutdownForExit(); zombie_shrapnel.ShutdownForExit(); zombie1_walk_e.ShutdownForExit(); zombie1_walk_n.ShutdownForExit(); zombie1_walk_w.ShutdownForExit(); zombie1_walk_s.ShutdownForExit(); zombie1_walk_sw.ShutdownForExit(); zombie1_walk_se.ShutdownForExit(); zombie1_walk_nw.ShutdownForExit(); zombie1_walk_ne.ShutdownForExit(); zombie2_walk_e.ShutdownForExit(); zombie2_walk_n.ShutdownForExit(); zombie2_walk_w.ShutdownForExit(); zombie2_walk_s.ShutdownForExit(); zombie2_walk_sw.ShutdownForExit(); zombie2_walk_se.ShutdownForExit(); zombie2_walk_nw.ShutdownForExit(); zombie2_walk_ne.ShutdownForExit(); zombie3_walk_e.ShutdownForExit(); zombie3_walk_n.ShutdownForExit(); zombie3_walk_w.ShutdownForExit(); zombie3_walk_s.ShutdownForExit(); zombie3_walk_sw.ShutdownForExit(); zombie3_walk_se.ShutdownForExit(); zombie3_walk_nw.ShutdownForExit(); zombie3_walk_ne.ShutdownForExit(); zombie1pit_death.ShutdownForExit(); zombie2pit_death.ShutdownForExit(); zombie3pit_death.ShutdownForExit(); zombie1lava_death.ShutdownForExit(); zombie2lava_death.ShutdownForExit(); zombie3lava_death.ShutdownForExit(); } if ((lurker_walk_e.anim_pointer != NULL) && (g_art_usage[LURKER] == FALSE) && (g_art_usage[DORMANT_REDCOAT] == FALSE)) { lurker_walk_e.ShutdownForExit(); lurker_walk_w.ShutdownForExit(); lurker_walk_n.ShutdownForExit(); lurker_walk_s.ShutdownForExit(); lurker_walk_se.ShutdownForExit(); lurker_walk_sw.ShutdownForExit(); lurker_walk_ne.ShutdownForExit(); lurker_walk_nw.ShutdownForExit(); lurker_wait.ShutdownForExit(); lurker_pit_death.ShutdownForExit(); lurker_lava_death.ShutdownForExit(); lurker_death_e.ShutdownForExit(); lurker_death_w.ShutdownForExit(); lurker_death_s.ShutdownForExit(); lurker_death_n.ShutdownForExit(); UnloadCel(lurker_piece_cel); lurker_piece_cel = (CCB *) NULL; } if ((meany_walk_e_w_n_s.anim_pointer != NULL) && (g_art_usage[MEANY] == FALSE)) { meany_walk_e_w_n_s.ShutdownForExit(); meany_walk_se_nw.ShutdownForExit(); meany_walk_ne_sw.ShutdownForExit(); meany_pit_death.ShutdownForExit(); meany_lava_death.ShutdownForExit(); meany_split.ShutdownForExit(); meany_stasis.ShutdownForExit(); meany_split_e.ShutdownForExit(); meany_split_w.ShutdownForExit(); meany_split_n.ShutdownForExit(); meany_split_s.ShutdownForExit(); nasty_walk_e_w_n_s.ShutdownForExit(); nasty_walk_se_nw.ShutdownForExit(); nasty_walk_ne_sw.ShutdownForExit(); nasty_pit_death.ShutdownForExit(); nasty_lava_death.ShutdownForExit(); nasty_split.ShutdownForExit(); nasty_stasis.ShutdownForExit(); nasty_split_e.ShutdownForExit(); nasty_split_w.ShutdownForExit(); nasty_split_n.ShutdownForExit(); nasty_split_s.ShutdownForExit(); grumpy_walk_e_w_n_s.ShutdownForExit(); grumpy_walk_se_nw.ShutdownForExit(); grumpy_walk_ne_sw.ShutdownForExit(); grumpy_pit_death.ShutdownForExit(); grumpy_lava_death.ShutdownForExit(); grumpy_death.ShutdownForExit(); } if ((jugger_walk_e.anim_pointer != NULL) && (g_art_usage[JUGGERNAUT] == FALSE)) { jugger_walk_e.ShutdownForExit(); jugger_walk_w.ShutdownForExit(); jugger_walk_n.ShutdownForExit(); jugger_walk_s.ShutdownForExit(); jugger_walk_se.ShutdownForExit(); jugger_walk_sw.ShutdownForExit(); jugger_walk_ne.ShutdownForExit(); jugger_walk_nw.ShutdownForExit(); jugger_pit_death.ShutdownForExit(); jugger_lava_death.ShutdownForExit(); jugger_death.ShutdownForExit(); } if ((psycho_walk_e.anim_pointer != NULL) && (g_art_usage[PSYCHO] == FALSE)) { psycho_walk_e.ShutdownForExit(); psycho_walk_w.ShutdownForExit(); psycho_walk_n.ShutdownForExit(); psycho_walk_s.ShutdownForExit(); psycho_walk_se.ShutdownForExit(); psycho_walk_sw.ShutdownForExit(); psycho_walk_ne.ShutdownForExit(); psycho_walk_nw.ShutdownForExit(); psycho_pit_death.ShutdownForExit(); psycho_lava_death.ShutdownForExit(); psycho_unmoving.ShutdownForExit(); psycho_death[0].ShutdownForExit(); psycho_death[1].ShutdownForExit(); psycho_death[2].ShutdownForExit(); } if ((beam_in_part1.anim_pointer != NULL) && (g_art_usage[SEEKER_MATERIALIZATION] == FALSE)) { beam_in_part1.ShutdownForExit(); beam_in_part2.ShutdownForExit(); }}/**************************** seeker::DumpMovementStatus ****************************** This routine is used for debugging purposes only.*****************************************************************************************/void seeker::DumpMovementStatus(dude *target){// if (target->move_status == NORMAL_MOVEMENT) printf("======== NORMAL ==============\n");// if (target->move_status == PRIME_DETOUR) printf("======== PRIME_DETOUR ========\n");// if (target->move_status == ALT_DETOUR) printf("======== ALT_DETOUR ==========\n");// if (target->move_status == HOUDINI_MODE) printf("======== HOUDINI_MODE ========\n");//// printf("target->stranded_counter: %ld\n",target->stranded_counter);// if (target->last_hazard != NULL)// printf("last hazard is at %ld, %ld and is of type %ld.\n",// target->last_hazard->ccb_XPos >> 16,target->last_hazard->ccb_YPos >> 16,// target->last_hazard_type);// // if (target->blocker != (solid_object *) NULL)// printf("obstruction is of type %ld\n",target->blocker->object_type);//// printf("Obstacle detour axis: ");// if (target->obstacle_detour_axis == NO_AXIS) printf(" ");// if (target->obstacle_detour_axis == X_AXIS) printf("X ");// if (target->obstacle_detour_axis == Y_AXIS) printf("Y ");//// printf("Old obstacle detour axis: ");// if (target->old_obstacle_detour_axis == NO_AXIS) printf(" ");// if (target->old_obstacle_detour_axis == X_AXIS) printf("X ");// if (target->old_obstacle_detour_axis == Y_AXIS) printf("Y ");// // printf("Obstacle detour direction: ");// if (target->obstacle_detour_direction == PLUS_DIRECTION) printf("+ ");// if (target->obstacle_detour_direction == MINUS_DIRECTION) printf("- ");// if (target->obstacle_detour_direction == NO_DIRECTION) printf(" ");// printf("\n");// // printf(" Hazard detour axis: ");// if (target->hazard_detour_axis == NO_AXIS) printf(" ");// if (target->hazard_detour_axis == X_AXIS) printf("X ");// if (target->hazard_detour_axis == Y_AXIS) printf("Y ");// // printf(" Hazard detour direction: ");// if (target->hazard_detour_direction == PLUS_DIRECTION) printf("+ ");// if (target->hazard_detour_direction == MINUS_DIRECTION) printf("- ");// if (target->hazard_detour_direction == NO_DIRECTION) printf(" ");// // printf(" Alt hazard direction: ");// if (target->alternate_hazard_direction == PLUS_DIRECTION) printf("+ ");// if (target->alternate_hazard_direction == MINUS_DIRECTION) printf("- ");// if (target->alternate_hazard_direction == NO_DIRECTION) printf(" ");// printf("\n");// // printf("\n");}/***************************************** EOF ******************************************/