// Filename : OBJECTS.C // Coded by : Scott Evans // Created/Modified : 15/2/98 // Description : Functions to handle objects #include OBJECT free_objects[MAX_OBJECTS]; OBJECT_LIST_HEADER free_objects_list; // Function : InitObjectList() // Coded by : Scott Evans // Created/Modified : 16/2/98 // Description : Initialise an object list // Parameters : h - pointer to list // Returns : None // Notes : None void InitObjectList(OBJECT_LIST_HEADER *h) { h->start=0; h->last=0; h->no_objects=0; } // Function : InitObjectFreeNodes() // Coded by : Scott Evans // Created/Modified : 15/2/98 // Description : Set up an a list of free nodes // Parameters : None // Returns : None // Notes : Need to call this before other list functions void InitObjectFreeNodes(void) { static u_byte initialised=0; u_word i; if(!initialised) { initialised=1; for(i=0;ino_objects++; // Get a free node new_object=free_objects_list.start; free_objects_list.start=new_object->next; new_object->next=new_object->previous=0; // Add new node to end of list if(h->start) { h->last->next=new_object; new_object->previous=h->last; } else h->start=new_object; h->last=new_object; return(new_object); } #ifdef DEBUG_INFO PrintFM("Failed\n"); #endif return(0); } // Function : RemoveObjectFromList() // Coded by : Scott Evans // Created/Modified : 15/2/98 // Description : Remove a node from a list // Parameters : h - pointer to header of list // dead_node - pointer to node to remove // Returns : None // Notes : None void RemoveObjectFromList(OBJECT_LIST_HEADER *h,OBJECT *dead_object) { OBJECT *object; // Are there any nodes to remove from list if(h->start) { h->no_objects--; // Is this the first object in the list object=dead_object->previous; if(object) object->next=dead_object->next; else h->start=dead_object->next; // Is this the last object in the list object=dead_object->next; if(object) object->previous=dead_object->previous; else h->last=dead_object->previous; // Put the dead object back on the free objects list dead_object->next=0; dead_object->previous=0; free_objects_list.last->next=dead_object; free_objects_list.last=dead_object; free_objects_list.no_objects++; } #ifdef DEBUG_INFO else PrintFM("Failed\n"); #endif } // Function : CreateObject() // Coded by : Scott Evans // Created/Modified : 16/2/98 // Description : Create a new object // Parameters : type - the type of object to create // Returns : Pointer to object, NULL for error // Notes : None OBJECT *CreateObject(OBJECT_LIST_HEADER *h,OBJECT_TYPE type) { OBJECT *new_object=AddObjectToList(h); if(new_object) { // No handler function as default SetObjectsHandler(new_object,NULL); // No velocity or acceleration SetObjectsVelocity(new_object,0,0,0); SetObjectsAcceleration(new_object,0,0,0); // Set its type new_object->type_code=type; // Default ot offset new_object->ot_offset=0; // No parent object new_object->parent=NULL; // Return new object return(new_object); } #ifdef DEBUG_INFO PrintFM("Failed"); #endif return(NULL); } // Function : SortObject() // Coded by : Scott Evans // Created/Modified : 16/2/98 // Description : Sort object into ordering table // Parameters : o - pointer to object // ot - ordering table // priority - ordering table priority // Returns : None // Notes : None void SortObject(OBJECT *o,GsOT *ot,u_word priority) { // Calculate ordering table position priority=(priority-o->ot_offset>0 ? priority-o->ot_offset : 0); switch(o->type_code) { case NULL_OBJECT: case SOUND_OBJECT: break; case PARTICLE_OBJECT: SortParticle(&o->type.p,ot,priority,&o->screen); break; case SPRITE_OBJECT: SortSprite(&o->type.s,ot,priority,&o->screen); break; case GUN_OBJECT: SortSprite(&o->type.g.s,ot,priority,&o->screen); break; case FAN_OBJECT: SortSprite(&o->type.f.s,ot,priority,&o->screen); break; case GsSPRITE_OBJECT: o->type.gss.x=o->screen.vx; o->type.gss.y=o->screen.vy; GsSortSprite(&o->type.gss,ot,priority); break; case GsTRIANGLE_OBJECT: o->type.gst.x0=o->screen.vx; o->type.gst.y0=o->screen.vy; o->type.gst.x1=o->screen.vx; o->type.gst.y1=o->screen.vy+o->h; o->type.gst.x2=o->screen.vx-o->w; o->type.gst.y2=o->screen.vy+(o->h>>1); GsSortTriangle(&o->type.gst,ot,priority); break; case GsGTRIANGLE_OBJECT: o->type.gsgt.x0=o->screen.vx; o->type.gsgt.y0=o->screen.vy; o->type.gsgt.x1=o->screen.vx; o->type.gsgt.y1=o->screen.vy+o->h; o->type.gsgt.x2=o->screen.vx-o->w; o->type.gsgt.y2=o->screen.vy+(o->h>>1); GsSortGTriangle(&o->type.gsgt,ot,priority); break; case GsTILE1_OBJECT: o->type.gstl1.x0=o->screen.vx; o->type.gstl1.y0=o->screen.vy; GsSortTile1(&o->type.gstl1,ot,priority); break; case GsTILE_OBJECT: o->type.gstl.x0=o->screen.vx; o->type.gstl.y0=o->screen.vy; o->type.gstl.w=o->w; o->type.gstl.h=o->h; GsSortTile(&o->type.gstl,ot,priority); break; case GsBOXF_OBJECT: o->type.gsbf.x=o->screen.vx; o->type.gsbf.y=o->screen.vy; o->type.gsbf.w=o->w; o->type.gsbf.h=o->h; GsSortBoxFill(&o->type.gsbf,ot,priority); break; case GsBOX_OBJECT: o->type.gsb.x=o->screen.vx; o->type.gsb.y=o->screen.vy; o->type.gsb.w=o->w; o->type.gsb.h=o->h; GsSortBox(&o->type.gsb,ot,priority); break; case GsGQUAD_OBJECT: o->type.gsgq.x0=o->screen.vx; o->type.gsgq.y0=o->screen.vy; o->type.gsgq.x1=o->screen.vx+o->w; o->type.gsgq.y1=o->screen.vy; o->type.gsgq.x2=o->screen.vx; o->type.gsgq.y2=o->screen.vy+o->h; o->type.gsgq.x3=o->screen.vx+o->w; o->type.gsgq.y3=o->screen.vy+o->h; GsSortGQuad(&o->type.gsgq,ot,priority); break; case GsQUAD_OBJECT: o->type.gsq.x0=o->screen.vx; o->type.gsq.y0=o->screen.vy; o->type.gsq.x1=o->screen.vx+o->w; o->type.gsq.y1=o->screen.vy; o->type.gsq.x2=o->screen.vx; o->type.gsq.y2=o->screen.vy+o->h; o->type.gsq.x3=o->screen.vx+o->w; o->type.gsq.y3=o->screen.vy+o->h; GsSortQuad(&o->type.gsq,ot,priority); break; case GsLINE3_OBJECT: GsSortLine3(&o->type.gsl3,ot,priority); break; case GsLINE2_OBJECT: GsSortLine2(&o->type.gsl2,ot,priority); break; default: #ifdef DEBUG_INFO sprintf(fm_string,"Failed (%d)\n",o->type_code); PrintFM(fm_string); #endif break; } } // Function : MoveObject() // Coded by : Scott Evans // Created/Modified : 16/2/98 // Description : Updates an objects position and velocity // Parameters : o - pointer to object // Returns : None // Notes : position, velocity and acceleration are fixed point numbers void MoveObject(OBJECT *o) { // Update position if(o->can_move) { o->position.vx+=o->velocity.vx; o->position.vy+=o->velocity.vy; o->position.vz+=o->velocity.vz; // Update screen coordinates o->screen.vx=o->position.vx>>FP24_8; o->screen.vy=o->position.vy>>FP24_8; o->screen.vz=o->position.vz>>FP24_8; // Update velocity of object o->velocity.vx+=o->acceleration.vx; o->velocity.vy+=o->acceleration.vy; o->velocity.vz+=o->acceleration.vz; } } // Function : SortObjects() // Coded by : Scott Evans // Created/Modified : 17/2/98 // Description : Add all objects to ordering table // Parameters : h - pointer to object list // ot - ordering table // priority - ordering table priority // Returns : None // Notes : None void SortObjects(OBJECT_LIST_HEADER *h,GsOT *ot,u_word priority) { OBJECT *object=h->start; // Go through each object in list while(object) { // Flash the object on and off if(object->blink) { if(GetTimer()&object->blink_rate) object->visible=1; else object->visible=0; } // Add it to the ordering table if it is visible if(object->visible) SortObject(object,ot,priority); // Next object in list object=object->next; } } // Function : UpdateObjects() // Coded by : Scott Evans // Created/Modified : 17/2/98 // Description : Update all the objects in a list // Parameters : h - pointer to object list // Returns : None // Notes : None void UpdateObjects(OBJECT_LIST_HEADER *h) { OBJECT *object=h->start,*next_object; SPRITE *spr; void (*object_handler)(OBJECT *); // Go through list of objects and update each of them while(object) { // Get next object, incase it gets killed next_object=object->next; // If object is active move it if(object->active) { MoveObject(object); // Do specifc stuff for object if((object_handler=object->f)) object_handler(object); } // Certain objects can be animated switch(object->type_code) { case SPRITE_OBJECT: spr=&object->type.s; break; case GUN_OBJECT: spr=&object->type.g.s; break; case FAN_OBJECT: spr=&object->type.f.s; break; default: spr=0; break; } if(spr && spr->animation_on) AnimateSprite(spr); object=next_object; } } // Function : ApplyWindToObjects() // Coded by : Scott Evans // Created/Modified : 20/2/98 // Description : Add wind effect to all objects // Parameters : w - wind object to apply // h - pointer to object list // Returns : None // Notes : None void ApplyWindToObjects(OBJECT *w,OBJECT_LIST_HEADER *h) { OBJECT *o=h->start; VIRTUAL_WIND *wind; long wind_x_force,wind_y_force; while(o) { wind=&w->type.w; if(o->type_code!=WIND_OBJECT && o->active && o->wind_effect && wind->blowing) { if(o->screen.vx>=w->screen.vx && o->screen.vx+o->w<=w->screen.vx+w->w && o->screen.vy>=w->screen.vy && o->screen.vy+o->h<=w->screen.vy+w->h) { wind_x_force=((wind->velocity.vx-o->velocity.vx)*wind->air_resistance.vx)>>FP24_8; wind_y_force=((wind->velocity.vy-o->velocity.vy)*wind->air_resistance.vy)>>FP24_8; o->velocity.vx+=wind_x_force; o->velocity.vy+=wind_y_force; o->in_wind=1; } } o=o->next; } } // Function : ApplyWindToObjects() // Coded by : Scott Evans // Created/Modified : 10/3/98 // Description : Add wind effect to all objects // Parameters : w - wind object list // h - pointer to object list // Returns : None // Notes : Apply all the winds to a list of objects void ApplyWindsToObjects(OBJECT_LIST_HEADER *w,OBJECT_LIST_HEADER *h) { OBJECT *o=h->start; // Clear the wind flags while(o) { o->in_wind=0; o=o->next; } o=w->start; while(o) { ApplyWindToObjects(o,h); o=o->next; } } // Function : SetObjectsBrightness() // Coded by : Scott Evans // Created/Modified : 24/2/98 // Description : Sets an objects colour // Parameters : o - pointer to object // b - pointer to brightness values // Returns : None // Notes : None void SetObjectsBrightness(OBJECT *o,BRIGHTNESS *b) { o->brightness.r=b->r; o->brightness.g=b->g; o->brightness.b=b->b; switch(o->type_code) { case NULL_OBJECT: break; case SPRITE_OBJECT: o->type.s.s.r=(b->r)>>FP12_4; o->type.s.s.g=(b->g)>>FP12_4; o->type.s.s.b=(b->b)>>FP12_4; break; case PARTICLE_OBJECT: SetParticleBrightness(&o->type.p,b); break; case GUN_OBJECT: o->type.g.s.s.r=(b->r)>>FP12_4; o->type.g.s.s.g=(b->g)>>FP12_4; o->type.g.s.s.b=(b->b)>>FP12_4; break; case FAN_OBJECT: o->type.f.s.s.r=(b->r)>>FP12_4; o->type.f.s.s.g=(b->g)>>FP12_4; o->type.f.s.s.b=(b->b)>>FP12_4; break; case GsSPRITE_OBJECT: o->type.gss.r=(b->r)>>FP12_4; o->type.gss.g=(b->g)>>FP12_4; o->type.gss.b=(b->b)>>FP12_4; break; case GsTRIANGLE_OBJECT: setRGB0(&o->type.gst,(b->r)>>FP12_4,(b->g)>>FP12_4,(b->b)>>FP12_4); break; case GsTILE1_OBJECT: setRGB0(&o->type.gstl1,(b->r)>>FP12_4,(b->g)>>FP12_4,(b->b)>>FP12_4); break; case GsTILE_OBJECT: setRGB0(&o->type.gstl,(b->r)>>FP12_4,(b->g)>>FP12_4,(b->b)>>FP12_4); break; case GsBOXF_OBJECT: o->type.gsbf.r=(b->r)>>FP12_4; o->type.gsbf.g=(b->g)>>FP12_4; o->type.gsbf.b=(b->b)>>FP12_4; break; case GsBOX_OBJECT: o->type.gsb.r=(b->r)>>FP12_4; o->type.gsb.g=(b->g)>>FP12_4; o->type.gsb.b=(b->b)>>FP12_4; break; case GsQUAD_OBJECT: setRGB0(&o->type.gsq,(b->r)>>FP12_4,(b->g)>>FP12_4,(b->b)>>FP12_4); break; case GsLINE3_OBJECT: setRGB0(&o->type.gsl3,(b->r)>>FP12_4,(b->g)>>FP12_4,(b->b)>>FP12_4); break; case GsLINE2_OBJECT: setRGB0(&o->type.gsl2,(b->r)>>FP12_4,(b->g)>>FP12_4,(b->b)>>FP12_4); break; default: #ifdef DEBUG_INFO sprintf(fm_string,"Failed (%d)\n",o->type_code); PrintFM(fm_string); #endif break; } } // Function : ClearObjectList() // Coded by : Scott Evans // Created/Modified : 25/2/98 // Description : Frees all objects in a list // Parameters : h - pointer to list to clear // Returns : None // Notes : None void ClearObjectList(OBJECT_LIST_HEADER *h) { while(h->start) RemoveObjectFromList(h,h->start); } // Function : FadeObjectsBrightness() // Coded by : Scott Evans // Created/Modified : 5/3/98 // Description : Fades all objects brightness // Parameters : o - pointer to object // b - pointer to brightness values // fade_speed - speed of transition // Returns : 0 if fade is finished, 1 if not // Notes : None u_byte FadeObjectsBrightness(OBJECT *o,BRIGHTNESS *b,u_word fade_speed) { BRIGHTNESS new; u_word dr,dg,db; u_byte status=0; while(o) { if(o->allow_fading) { dr=((b->r-o->brightness.r)<g-o->brightness.g)<b-o->brightness.b)<is_fading=1; else o->is_fading=0; new.r=o->brightness.r+dr; new.g=o->brightness.g+dg; new.b=o->brightness.b+db; SetObjectsBrightness(o,&new); status|=o->is_fading; } o=o->next; } return(status); } // Function : FadeObjectBrightness() // Coded by : Scott Evans // Created/Modified : 5/3/98 // Description : Fades a single objects brightness // Parameters : o - pointer to object // b - pointer to new brightness values // fade_speed - speed of transition // Returns : 0 if fade is finished, 1 if not // Notes : None u_byte FadeObjectBrightness(OBJECT *o,BRIGHTNESS *b,u_word fade_speed) { BRIGHTNESS new; u_word dr,dg,db; if(o->allow_fading) { dr=((b->r-o->brightness.r)<g-o->brightness.g)<b-o->brightness.b)<is_fading=1; else o->is_fading=0; new.r=o->brightness.r+dr; new.g=o->brightness.g+dg; new.b=o->brightness.b+db; SetObjectsBrightness(o,&new); } return(o->is_fading); } // Function : Object2Object() // Coded by : Scott Evans // Created/Modified : 5/3/98 // Description : Test for collisions between 2 objects // Parameters : o - pointer to object // o1 - pointer to 2nd object // Returns : 1 objects have collided, 0 if no collision // Notes : None u_byte Object2Object(OBJECT *o,OBJECT *o1) { return(BoundingBoxTest(&o->box,&o1->box)); } // Function : FindLastObjectInList() // Coded by : Scott Evans // Created/Modified : 16/4/98 // Description : Find the last object in a list // Parameters : l - pointer to list // Returns : Last object in list, NULL if empty list // Notes : None OBJECT *FindLastObjectInList(OBJECT_LIST_HEADER *l) { OBJECT *o=l->start; while(o->next) o=o->next; return(o); }