void *memAllocFunction(sdword length, udword flags) #endif { ubyte *newPointer = NULL; #if MEM_ERROR_CHECKING if (length <= 0) { dbgFatalf(DBG_Loc, "Attempted to allocate %d bytes of '%s'", length, name); } #endif #if MEM_USE_NAMES newPointer = memAllocAttempt(length, name, flags); //call the main allocation routine #else newPointer = memAllocAttempt(length, 0, flags); //call the main allocation routine #endif if (newPointer == NULL) //if failure { #if MEM_USE_NAMES dbgFatalf(DBG_Loc, "memAlloc: failed to allocate %d bytes of %s", length, name); #else dbgFatalf(DBG_Loc, "memAlloc: failed to allocate %d bytes", length); #endif } return(newPointer); }
void scriptSetBarsToDo(char *directory,char *field,void *dataToFillIn) { HorseRaceBars *barsToDo = (HorseRaceBars *)dataToFillIn; sdword i; char *miscPointer; barsToDo->numBars = 0; miscPointer = strtok(field, " \t,"); if (miscPointer != NULL) { sscanf(miscPointer, "%d", &barsToDo->numBars); } for (i=0;i<barsToDo->numBars;i++) { if ((miscPointer = strtok(NULL, " \t,")) != NULL) { sscanf(miscPointer, "%f", &barsToDo->perc[i]); } else { dbgFatalf(DBG_Loc,"Invalid specification in tweak.script %s",field); } } }
/*----------------------------------------------------------------------------- Name : binkInit Description : Inputs : Outputs : Return : TRUE or FALSE (success or failure) ----------------------------------------------------------------------------*/ bool binkInit(sdword rgltype) { sdword size; g_RGLtype = rgltype; binkSemaphore = CreateSemaphore(NULL, 1, 1, BINK_SemaphoreName); dbgAssert(binkSemaphore != NULL); switch (g_RGLtype) { case SWtype: size = 2; break; case -1: case GLtype: case D3Dtype: size = 4; break; default: dbgFatalf(DBG_Loc, "what's this type: %d [binkInit]", g_RGLtype); } binkSurface = (uword*)radmalloc(size*640*480); binkTimeReset(); return TRUE; }
/*----------------------------------------------------------------------------- Name : madLinkInSetUpInitialBuiltMadState Description : For ships like the defender, probe, etc... they need to have animations started then paused upon creation. This function does that. Inputs : Ship to have animation set up Outputs : Return : ----------------------------------------------------------------------------*/ void madLinkInSetUpInitialPlacedMadState(Ship *ship) { #if DEBUG_MESH_ANIMATIONS dbgAssertOrIgnore(ship->madBindings != NULL); #endif if(ship->staticinfo->madStatic->needStartPlacedAnimation) { //if ship has need to be set to a specific starting animation madAnimationStart(ship, ship->staticinfo->madStatic->startPlacedAnimationIndex); madAnimationPause(ship, !ship->madBindings->bPaused); switch(ship->shiprace) { case R1: switch(ship->shiptype) { case HeavyDefender: ship->madGunStatus = MAD_STATUS_GUNS_CLOSED; break; default: break; } break; case R2: case P1: case P2: case P3: case Traders: break; default: dbgFatalf(DBG_Loc,"\nUnknown race type with a start up mesh animation (1)."); } } }
/*----------------------------------------------------------------------------- Name : madAnimationStart Description : Start an animation playing for a given ship Inputs : ship - ship to play the animation for animNumber - index of the animation rate - rate of the animation 1.0 is normal animation speed. -1 plays animation in reverse. Outputs : sets time, rate and splinecurves up for an animation. Return : void ----------------------------------------------------------------------------*/ void madAnimationStart(Ship *ship, sdword animNumber) { madanim *anim = ship->madBindings; madheader *header = anim->header; shipbindings *bindings = &anim->bindings; sdword index, j, startPoint; splinecurve *curve; madanimation *animation; udword animBit = (1 << animNumber); //if the ship has gun bindings, swap the animation bindings with the gun bindings anim->saveBindings = ship->bindings; ship->bindings = bindings; dbgAssertOrIgnore(animNumber < header->nAnimations); anim->nCurrentAnim = animNumber; animation = &header->anim[animNumber]; anim->startTime = anim->time = animation->startTime; anim->timeElapsed = 0.0f; //start all the b-splines. They've already been set up, //we just need to initialize the time and current point. curve = anim->curves; for (index = 0; index < header->nObjects; index++) { if (!bitTest(header->objPath[index].animationBits, animBit)) { //if this object doesn't need to participate in the animation curve->currentPoint = BS_NoPoint; //set the curves to not update curve += 6; continue; } for (startPoint = 0; startPoint < curve->nPoints; startPoint++) { if (curve->times[startPoint] == anim->time) { goto foundTime; } } #if MAD_ERROR_CHECKING dbgFatalf(DBG_Loc, "madAnimationStart: Object #%d ('%s') has no keyframe at frame %.0f", index, header->objPath[index].name, anim->time / header->framesPerSecond); #endif foundTime: for (j = 0; j < 6; j++, curve++) { curve->timeElapsed = anim->time; curve->currentPoint = startPoint; } } #if MAD_VERBOSE_LEVEL >= 2 dbgMessagef("madAnimationStart: started animation #%d('%s') on ship 0x%x", animNumber, animation->name, ship); #endif }
sdword lodAutoSave(lodinfo *LOD) { sdword level; FILE *fp; char *filePath; real32 baseScalar = 1.0f, stripeScalar = 1.0f; fp = fopen(LOD->fileName, "wt"); if (fp == NULL) { dbgWarningf(DBG_Loc, "Cannot open '%s' for writing - not checked out?", LOD->fileName); return(ERROR); } fprintf(fp, "[Auto-Saved LOD file]\n"); fprintf(fp, "pointColor %d,%d,%d\n\n", colRed(LOD->pointColor), colGreen(LOD->pointColor), colBlue(LOD->pointColor)); for (level = 0; level < LOD->nLevels; level++) { fprintf(fp, "\n"); if (LOD->level[level].baseScalar != baseScalar) { baseScalar = LOD->level[level].baseScalar; fprintf(fp, "baseScalar %.2f\n", baseScalar == 0.0f ? 1.0f : baseScalar); } if (LOD->level[level].stripeScalar != stripeScalar) { stripeScalar = LOD->level[level].stripeScalar; fprintf(fp, "stripeScalar %.2f\n", stripeScalar == 0.0f ? 1.0f : stripeScalar); } fprintf(fp, "type%d %s\n", level, lodTypeStrings[LOD->level[level].flags & LM_LODType]); if ((LOD->level[level].flags & LM_LODType) == LT_Mesh) { filePath = strchr(((meshdata *)LOD->level[level].pData)->fileName, '\\') + 1; #if LOD_ERROR_CHECKING if (*filePath == 0) { dbgFatalf(DBG_Loc, "Could not find '\\' in '%s'", ((meshdata *)LOD->level[level].pData)->fileName); } #endif fprintf(fp, "pMeshFile%d %s\n", level, filePath); } fprintf(fp, "mOn%d %.1f\n", level, LOD->level[level].mOn); fprintf(fp, "bOn%d %.0f\n", level, LOD->level[level].bOn); fprintf(fp, "mOff%d %.1f\n", level, LOD->level[level].mOff); fprintf(fp, "bOff%d %.0f\n", level, LOD->level[level].bOff); } fclose(fp); return(0); }
/*----------------------------------------------------------------------------- Name : madAnimIndexFindByName Description : Find the index of an animation by name Inputs : header - header to search name - name of animation to find Outputs : Return : index of animation, generates an error if not found ----------------------------------------------------------------------------*/ sdword madAnimIndexFindByName(madheader *header, char *name) { sdword index; dbgAssertOrIgnore(header->stringBlock != NULL); for (index = 0; index < header->nAnimations; index++) { if (strcasecmp(header->anim[index].name, name) == 0) { return(index); } } dbgFatalf(DBG_Loc, "Unable to find animation '%s'.", name); return(-1); }
static void lightTypeSet(char *directory,char *field,void *dataToFillIn) { sdword index; for (index = 0; lightNameToInfoTable[index].name != NULL; index++) { if (strcmp(lightNameToInfoTable[index].name, field) == 0) { //if names match currentLight = lightNameToInfoTable[index].light; return; } } #if LIGHT_ERROR_CHECKING dbgFatalf(DBG_Loc, "light type %s not known.", field); #endif }
void ProcessTransferCaptaincyPacket(TransferCaptaincyPacket *packet) { CaptaincyCustomInfo *custominfo = NULL; udword misc = packet->packetheader.frame; uword from = packet->packetheader.from; if (packet->subtype & XFERCAP_CUSTOMINFO_PRESENT) { custominfo = &packet->custominfo; } switch (packet->subtype & XFERCAP_SUBTYPE_MASK) { case XFERCAP_GIVEUP_CAPTAINCY_NOTICE: if (misc == captainIndex) // only pass through if active captain is giving up captaincy { captainIndex = -1; receiveSyncPacketsFrom = -1; // don't accept packets from me TransferCaptaincyStateMachine(CAPEVENT_GIVEUP_CAPTAINCY_NOTICE,from,misc,custominfo); } break; case XFERCAP_CAPTAIN_PROPOSAL: TransferCaptaincyStateMachine(CAPEVENT_CAPTAIN_PROPOSAL,from,misc,custominfo); break; case XFERCAP_PAUSE_TRANSFERRING_CAPTAIN: TransferCaptaincyStateMachine(CAPEVENT_PAUSE_TRANSFERRING_CAPTAIN,from,misc,custominfo); break; case XFERCAP_PAUSE_ACK: TransferCaptaincyStateMachine(CAPEVENT_PAUSE_ACK,from,misc,custominfo); break; case XFERCAP_PAUSE_YOU_BE_CAPTAIN: TransferCaptaincyStateMachine(CAPEVENT_PAUSE_YOU_BE_CAPTAIN,from,misc,custominfo); break; case XFERCAP_I_AM_NEW_CAPTAIN: AcknowledgeNewCaptain(misc); TransferCaptaincyStateMachine(CAPEVENT_I_AM_NEW_CAPTAIN,from,misc,custominfo); break; default: dbgFatalf(DBG_Loc,"Invalid transfer captaincy packet"); break; } }
void svShipManeuverability(ShipStaticInfo *statinfo,char *name) { sdword man=0; real32 turnspeed; if(statinfo->svManeuverability != 0) { man = statinfo->svManeuverability; calcmanjump: switch (man) { case 1: //very low sprintf(name,"%s",ShipStatToNiceStr(VeryLow)); break; case 2: //low sprintf(name,"%s",ShipStatToNiceStr(Low)); break; case 3: //medium sprintf(name,"%s",ShipStatToNiceStr(Medium)); break; case 4: //high sprintf(name,"%s",ShipStatToNiceStr(High)); break; case 5: //Very High sprintf(name,"%s",ShipStatToNiceStr(VeryHigh)); break; default: dbgFatalf(DBG_Loc,"Error Calculating Maneuverability"); } return; } //calculate maneuverability turnspeed = statinfo->turnspeedstat[TURN_YAW]+ statinfo->turnspeedstat[TURN_PITCH]+ statinfo->turnspeedstat[TURN_ROLL]; if(turnspeed < TW_SV_MAN_VERY_LOW) man=1; else if(turnspeed < TW_SV_MAN_LOW) man=2; else if(turnspeed < TW_SV_MAN_MEDIUM) man=3; else if(turnspeed < TW_SV_MAN_HIGH) man=4; else man=5; goto calcmanjump; }
/*----------------------------------------------------------------------------- Name : taskPointerAlloc Description : Allocate a task pointer out of global task data list Inputs : void Outputs : sets allocated task pointer to -1 Return : index of newly allocated task Note : generates a fatal error if no task found ----------------------------------------------------------------------------*/ sdword taskPointerAlloc(void) { sdword index; for (index = 0; index < TSK_NumberTasks; index++) //look for a free task { if (taskData[index] == NULL) //if free { taskData[index] = (void *)0xffffffff; taskMaxTask = max(taskMaxTask, index + 1); //update max task if needed return(index); } } #if TASK_ERROR_CHECKING dbgFatalf(DBG_Loc, "All %d task pointers in use.", taskMaxTask); #endif return(ERROR); }
/*----------------------------------------------------------------------------- Name : taskStartName Description : Start a specific task Inputs : function - entry point of task name - a string describing the task for debugging period - period between consecutive calls stacksize - size of task's local stack flags - control execution of task Outputs : taskdata structure allocated and initialized Return : handle to task for later manipulation of task Note : if a taskdata structure or stack RAM cannot be allocated, the function will generate a fatal error. name must be caller-allocated and outlive the task. This is usually invoked with the taskStart macro. The task is executed once immediately and must yield rather than exit at this first call. ----------------------------------------------------------------------------*/ taskhandle taskStartName(taskfunction function, char *name, real32 period, udword flags) { static taskhandle handle = ERROR; taskdata *newTask; taskInitCheck(); dbgAssertOrIgnore(function != NULL); dbgAssertOrIgnore(period > 0.0f); newTask = memAlloc(sizeof(taskdata), "taskData", NonVolatile); handle = taskPointerAlloc(); taskData[handle] = newTask; #if TASK_VERBOSE_LEVEL >= 2 dbgMessagef("%s: starting task at 0x%x at %d Hz, flags 0x%x using handle %d at 0x%x", __FUNCTION__, function, 1.0f/period, flags, handle, taskData[handle]); #endif //make task in use and running newTask->flags = flags | TF_Allocated; newTask->function = function; newTask->context = NULL; newTask->name = name; newTask->ticks = 0; //no residual ticks dbgAssertOrIgnore(period * taskFrequency < (real32)SDWORD_Max); newTask->ticksPerCall = (udword)(period * taskFrequency); function(&newTask->context); if (newTask->context == NULL) { // Exited already? #if TASK_ERROR_CHECKING dbgFatalf(DBG_Loc, "taskStart: stillborn task %s", name); #endif taskStop(handle); return ERROR; } return handle; }
//set correct LOD type static void lodTypeRead(char *directory,char *field,void *dataToFillIn) { //set correct LOD type lod *dest; dest = (lod *)dataToFillIn; #if LOD_AUTO_SAVE dest->baseScalar = (trBaseColorScalar == 0.0f) ? 1.0f : trBaseColorScalar; dest->stripeScalar = (trStripeColorScalar == 0.0f) ? 1.0f : trStripeColorScalar; #endif _strupr(field); if (strstr(field, "INVALID")) { dest->flags = (udword)((dest->flags & (~LM_LODType)) | LT_Invalid); } else if (strstr(field, "MESH")) { dest->flags = (udword)((dest->flags & (~LM_LODType)) | LT_Mesh); } else if (strstr(field, "TINYSPRITE")) { dest->flags = (udword)((dest->flags & (~LM_LODType)) | LT_TinySprite); } else if (strstr(field, "SUBPIXEL")) { dest->flags = (udword)((dest->flags & (~LM_LODType)) | LT_SubPixel); } else if (strstr(field, "FUNCTION")) { dest->flags = (udword)((dest->flags & (~LM_LODType)) | LT_Function); } else if (strstr(field, "NULL")) { dest->flags = (udword)((dest->flags & (~LM_LODType)) | LT_NULL); } #if LOD_ERROR_CHECKING else { dbgFatalf(DBG_Loc, "Invalid LOD type: '%s'", field); } #endif }
/*----------------------------------------------------------------------------- Name : binkUserPaintCallback Description : Inputs : psurf - surface pointer or NULL pitch, x, y - ignored Outputs : frame is blitted onto binkSurface Return : ----------------------------------------------------------------------------*/ static void binkUserPaintCallback(void* psurf, sdword pitch, sdword x, sdword y) { WaitForSingleObject(binkSemaphore, INFINITE); binkDisplayFlags = BINKSURFACECOPYALL; if (psurf != NULL) { BinkCopyToBuffer(bnk, psurf, pitch, 480, x, y, BINKSURFACE565 | binkDisplayFlags); } else { switch (g_RGLtype) { case -1: if (pitch == 2*640) { BinkCopyToBuffer(bnk, binkSurface, pitch, 480, 0, 0, ((g_surfType == S_RGB565) ? BINKSURFACE565 : BINKSURFACE555) | binkDisplayFlags); } else { BinkCopyToBuffer(bnk, binkSurface, pitch, 480, 0, 0, BINKSURFACE32 | binkDisplayFlags); } break; case SWtype: BinkCopyToBuffer(bnk, binkSurface, 2*640, 480, 0, 0, ((g_surfType == S_RGB565) ? BINKSURFACE565 : BINKSURFACE555) | binkDisplayFlags); break; case GLtype: case D3Dtype: BinkCopyToBuffer(bnk, binkSurface, 4*640, 480, 0, 0, BINKSURFACE32 | binkDisplayFlags); break; default: dbgFatalf(DBG_Loc, "what's this type: %d [binkUserPaintCallback]", g_RGLtype); } } ReleaseSemaphore(binkSemaphore, 1, NULL); }
sdword aieHandlerToNum(aieHandlerSimple handler) { if (handler == NULL) { return -1; } else { sdword i = 0; while (handlerTable[i] != NULL) { if (handlerTable[i] == handler) { return i; } i++; } dbgFatalf(DBG_Loc,"Save Game: Unknown Handler"); return -1; } }
void TimeoutTimerTimedOut(sdword timer) { switch (timer) { case T1: TimeoutTimerReset(timer); TransferCaptaincyStateMachine(CAPEVENT_TIMEOUT1,0,0,NULL); break; case T2: TimeoutTimerReset(timer); TransferCaptaincyStateMachine(CAPEVENT_TIMEOUT2,0,0,NULL); break; case TWAITFORPAUSEACKS: TimeoutTimerReset(timer); TransferCaptaincyStateMachine(CAPEVENT_TWAITFORPAUSEACKS,0,0,NULL); break; default: dbgFatalf(DBG_Loc,"Unknown timer %d timed out",timer); break; } }
/*----------------------------------------------------------------------------- Name : sdDumpFileLoad Description : Load in the stack dump file. Inputs : dumpFile - path and name of file to load Outputs : Return : void ----------------------------------------------------------------------------*/ void sdDumpFileLoad(char *dumpFile) { FILE *fp; sdword length, nRead; udword *readPtr; fp = fopen(dumpFile, "rb"); if (fp == NULL) { dbgFatalf(DBG_Loc, "Cannot open dump file '%s'", dumpFile); } printf("\nLoading dump file '%s'", dumpFile); length = fseek(fp, 0, SEEK_END); //get length of file dbgAssert(length == 0); length = ftell(fp); rewind(fp); sdDumpLength = length / sizeof(udword); nRead = fread(&sdStackReference, sizeof(udword), 1, fp);//first dword is the reference label "dbgFatalf" dbgAssert(nRead == 1); length -= sizeof(udword); nRead = fread(&sdReferenceAddress, sizeof(udword), 1, fp);//first dword is the reference label "dbgFatalf" dbgAssert(nRead == 1); length -= sizeof(udword); readPtr = sdDump = memAlloc(length, "Dump", 0); sdStackOffset = sdStackReference - (udword)sdDump; //compute stack offset length /= sizeof(udword); while (length) { nRead = fread(readPtr, sizeof(udword), 1, fp); dbgAssert(nRead == 1); length--; readPtr++; } fclose(fp); }
bool HeavyCorvetteSpecialTarget(Ship *ship, void *custom) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; SelectAnyCommand *targets = (SelectAnyCommand *)custom; real32 tempreal; vector Av; sdword i,flag; if(spec->cooldown) { aitrackSteadyShip(ship); return FALSE; } if (targets->numTargets == 0) { return TRUE; } switch(spec->burstState) { case BURST_Begin: //get average position of targets vecSet(Av,0.0f,0.0f,0.0f); for(i=0;i<targets->numTargets;i++) { vecAddTo(Av,targets->TargetPtr[i]->collInfo.collPosition); } tempreal = 1.0f/((real32)i); vecScalarMultiply(spec->burstFireVector,Av,tempreal); /////////////////////////////// /////burst attack speech event! //event num: COMM_HVette_BurstAttack //use battle chatter if(ship->playerowner->playerIndex == universe.curPlayerIndex) { if(ship->playerowner->playerIndex == universe.curPlayerIndex) { if (battleCanChatterAtThisTime(BCE_COMM_HVette_BurstAttack, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_COMM_HVette_BurstAttack, ship, SOUND_EVENT_DEFAULT); } } } /////////////////////////////// spec->burstState=BURST_FlyToFirePoint; break; case BURST_FlyToFirePoint: flag = 0; if(doBurstCharging(ship)) { //ship is fully charged flag = 1; } if(flytoBurstPosition(ship)) { //ship is in position fire if(flag == 1) { spec->burstState=BURST_Fire; } } break; case BURST_Fire: if(doBurstFire(ship)) { spec->burstState = BURST_Begin; dbgMessagef("Firing Burst Fire."); } break; default: dbgFatalf(DBG_Loc,"\nUnknown BurstState %d for shiptype %d.",spec->burstState,ship->shiptype); } //perform burst attack AI here... return FALSE; }
void horseGetNumBars(HorseRaceBars *horsebars) { sdword i; bool enablebar[MAX_POSSIBLE_NUM_BARS]; real32 totalperc; dbgAssertOrIgnore(horseTotalNumBars.numBars > 0); for (i=0;i<horseTotalNumBars.numBars;i++) { switch (i) { case DOWNLOADMAP_BAR: enablebar[i] = autodownloadmapRequired(); break; case UNIVERSE_BAR: enablebar[i] = TRUE; break; case ETG_BAR: enablebar[i] = etgHasBeenStarted ? FALSE : TRUE; break; case TEXTURE1_BAR: case TEXTURE2_BAR: #if TR_NIL_TEXTURE enablebar[i] = GLOBAL_NO_TEXTURES ? FALSE : TRUE; #else enablebar[i] = TRUE; #endif break; default: dbgFatalf(DBG_Loc,"You must specify whether or not to load bar %i here",i); break; } } horsebars->numBars = 0; // now, based on enablebar[i], selectively add bars that will be loaded: for (i=0;i<horseTotalNumBars.numBars;i++) { if (enablebar[i]) { horsebars->perc[horsebars->numBars++] = horseTotalNumBars.perc[i]; } } dbgAssertOrIgnore(horsebars->numBars > 0); // now renormalize percentages to 1.0 for (totalperc = 0.0f,i=0;i<horsebars->numBars;i++) { totalperc += horsebars->perc[i]; } dbgAssertOrIgnore(totalperc > 0.0f); if (totalperc != 1.0f) { for (i=0;i<horsebars->numBars;i++) { horsebars->perc[i] /= totalperc; } } }
/*----------------------------------------------------------------------------- Name : madLinkInUpdateMeshAnimations Description : starts,stops and does whatever needs to be done for mesh animations based on code given cues. Inputs : Ship to have animation updated Outputs : Return : ----------------------------------------------------------------------------*/ void madLinkInUpdateMeshAnimations(Ship *ship) { if(bitTest(ship->madAnimationFlags,MAD_NEED_TO_START_NEW_ANIMATION)) { //we need to switch to a new animation for some odd reason if(ship->madBindings->nCurrentAnim != MAD_NoAnimation) { if(ship->madBindings->bPaused) { //animation is paused...well,unpause it //so as to fix a bug in lukes code! madAnimationPause(ship,!ship->madBindings->bPaused); } madAnimationStop(ship); } madAnimationStart(ship, ship->cuedAnimationIndex); //start 0th cued animation /* play special animation sound here */ soundEvent(ship, ship->soundEventAnimationTypeFlag); bitClear(ship->madAnimationFlags,MAD_NEED_TO_START_NEW_ANIMATION); if(ship->shiptype == Mothership) { MothershipDoorUpKeep(ship); } return; } //time to start animation if(madAnimationUpdate(ship, universe.phystimeelapsed)) { #if DEBUG_MESH_ANIMATIONS dbgMessagef("Animation Finished."); #endif //start and pause poo here for pooeyness...(wings just closed, gotta stay closed...etc.. //cleanup ended animation switch(ship->cuedAnimationType) { case MAD_ANIMATION_GUN_OPENING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madGunStatus = MAD_STATUS_GUNS_OPEN; break; case MAD_ANIMATION_GUN_CLOSING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madGunStatus = MAD_STATUS_GUNS_CLOSED; //setup closed gun hack... madAnimationStart(ship, ship->staticinfo->madStatic->gunOpenIndexes[0]); //start 0th animation madAnimationPause(ship,!ship->madBindings->bPaused); break; case MAD_ANIMATION_WINGS_OPENING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madWingStatus = MAD_STATUS_WINGS_OPEN; break; case MAD_ANIMATION_WINGS_CLOSING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madWingStatus = MAD_STATUS_WINGS_CLOSED; //setup closed gun hack... madAnimationStart(ship, ship->staticinfo->madStatic->PostDockIndexes[0]); //start 0th animation madAnimationPause(ship,!ship->madBindings->bPaused); break; case MAD_ANIMATION_DOOR_OPENING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madDoorStatus = MAD_STATUS_DOOR_OPEN; madAnimationStart(ship, ship->staticinfo->madStatic->DoorCloseIndexes[0]); //start 0th animaiton madAnimationPause(ship,!ship->madBindings->bPaused); break; case MAD_ANIMATION_DOOR_CLOSING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madDoorStatus = MAD_STATUS_DOOR_CLOSED; // play the mothership door closed sound (big Ka-chunk) // this is in addition to the closing sound which is triggered at the start of closing soundEvent(ship, Ship_MoshipDoorClosed); break; case MAD_ANIMATION_SPECIAL_OPENING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madSpecialStatus = MAD_STATUS_SPECIAL_OPEN; break; case MAD_ANIMATION_SPECIAL_CLOSING: ship->cuedAnimationType = MAD_ANIMATION_NOTHING; ship->madSpecialStatus = MAD_STATUS_SPECIAL_CLOSED; madAnimationStart(ship, ship->staticinfo->madStatic->specialOpenIndexes[0]); //start 0th animaiton madAnimationPause(ship,!ship->madBindings->bPaused); break; } bitClear(ship->madAnimationFlags,MAD_ANIMATION_NEED_PROC); //play animations that are waiting... if(ship->nextAnim != 0) { switch(ship->nextAnim) { case MAD_ANIMATION_GUN_OPENING: madOpenGunsShip(ship); break; case MAD_ANIMATION_GUN_CLOSING: madLinkInCloseGunsShip(ship); break; case MAD_ANIMATION_WINGS_OPENING: madLinkInPostDockingShip(ship); break; case MAD_ANIMATION_WINGS_CLOSING: madLinkInPreDockingShip(ship); break; case MAD_ANIMATION_DOOR_OPENING: madLinkInOpenDoor(ship); break; case MAD_ANIMATION_DOOR_CLOSING: madLinkInCloseDoor(ship); break; case MAD_ANIMATION_SPECIAL_OPENING: madLinkInOpenSpecialShip(ship); break; case MAD_ANIMATION_SPECIAL_CLOSING: madLinkInCloseSpecialShip(ship); break; default: dbgFatalf(DBG_Loc,"\nUnknown animation in nextAnim variable."); break; } ship->nextAnim = 0; } } if(ship->shiptype == Mothership) { MothershipDoorUpKeep(ship); } }
/*----------------------------------------------------------------------------- Name : madAnimBindingUpdate Description : Mesh binding function for scripted mesh animations. Inputs : flags - ignored startMatrix - initial matrix data - pointer to ship ID - index of object path in the animation for this ship Outputs : matrixDest - animated matrix Return : TRUE = matrix updated ----------------------------------------------------------------------------*/ bool madAnimBindingUpdate(udword flags, hmatrix *startMatrix, hmatrix *matrixDest, void *data, sdword ID) { real32 timeElapsed; Ship *ship = (Ship *)data; sdword j, startPoint; madheader *header; madanim *anim = ship->madBindings; madobjpath *path; madanimation *animation; splinecurve *curve; vector hpb, xyz; matrix _3x3Matrix; hmatrix rotMatrix; #if MR_TEST_HPB if (mrTestHPBMode && ID == madTestHPBIndex) { hpb.x = mrHeading; hpb.y = mrPitch; hpb.z = mrBank; curve = &anim->curves[ID * 6]; //pointer to spline curves for this object xyz.x = curve[0].points[0]; xyz.y = curve[1].points[0]; xyz.z = curve[2].points[0]; nisObjectEulerToMatrix(&_3x3Matrix, &hpb); //make a rotation matrix hmatMakeHMatFromMatAndVec(&rotMatrix, &_3x3Matrix, &xyz);//make a hmatrix *matrixDest = rotMatrix; return(TRUE); } #endif dbgAssertOrIgnore(anim != NULL); curve = &anim->curves[ID * 6]; //pointer to spline curves for this object if (curve->currentPoint == BS_NoPoint) { //if this object not animating *matrixDest = *startMatrix; return(FALSE); //don't bother updating animation } timeElapsed = anim->timeElapsed; header = anim->header; //pointer to animation data path = &header->objPath[ID]; //pointer to motion path animation = &header->anim[anim->nCurrentAnim]; //pointer to animation header if (curve[0].timeElapsed + timeElapsed > animation->endTime) { //if we'll go past the end if (bitTest(animation->flags, MAF_Loop)) { //if this is a looping animation timeElapsed = (real32)fmod((double)(curve[0].timeElapsed + timeElapsed - animation->endTime), (double)(animation->endTime - animation->startTime)); for (startPoint = 0; startPoint < curve[0].nPoints; startPoint++) { //find a point to restart at if (curve[0].times[startPoint] == anim->startTime) { goto foundTime; } } #if MAD_ERROR_CHECKING dbgFatalf(DBG_Loc, "madAnimationStart: Object #%d ('%s') has no keyframe at frame %.0f", anim->nCurrentAnim, header->objPath[anim->nCurrentAnim].name, anim->startTime / header->framesPerSecond); #endif foundTime: for (j = 0; j < 6; j++) { //reset all the motion curves curve[j].timeElapsed = animation->startTime; curve[j].currentPoint = startPoint; } } else { //else it's a non-looping animation; clamp at the end timeElapsed = animation->endTime - curve[0].timeElapsed;//clamp to end } } //now update the motion curves xyz.x = bsCurveUpdate(&curve[1], timeElapsed); xyz.y = bsCurveUpdate(&curve[2], timeElapsed); xyz.z = -bsCurveUpdate(&curve[0], timeElapsed); hpb.x = bsCurveUpdate(&curve[3], timeElapsed); hpb.y = bsCurveUpdate(&curve[4], timeElapsed); hpb.z = bsCurveUpdate(&curve[5], timeElapsed); dbgAssertOrIgnore(xyz.x != REALlyBig && xyz.y != REALlyBig && xyz.z != REALlyBig); dbgAssertOrIgnore(hpb.x != REALlyBig && hpb.y != REALlyBig && hpb.z != REALlyBig); nisObjectEulerToMatrix(&_3x3Matrix, &hpb); //make a rotation matrix hmatMakeHMatFromMatAndVec(&rotMatrix, &_3x3Matrix, &xyz); //make a hmatrix *matrixDest = rotMatrix; //remember when this curve was last updated return(TRUE); }
/*----------------------------------------------------------------------------- Name : madFileLoad Description : Load in a .MAD mesh animation file Inputs : fileName - name of file to load Outputs : Return : newly allocated animation data Note : the string block for binding information is allocated as a separate block of memory so it can be freed after all animation binding is complete. ----------------------------------------------------------------------------*/ madheader *madFileLoad(char *fileName) { madheader header; madheader *newHeader; sdword index, j; filehandle file; sdword fileSize; #ifdef _X86_64 char newFileName[80]; sprintf(newFileName, "%s.64",fileName); fileName = newFileName; #endif dbgAssertOrIgnore(fileName != NULL); fileSize = fileSizeGet(fileName, 0); file = fileOpen(fileName, 0); fileBlockRead(file, &header, madHeaderSize(0)); #if FIX_ENDIAN header.version = FIX_ENDIAN_FLOAT_32( header.version ); header.stringBlockLength = FIX_ENDIAN_INT_32( header.stringBlockLength ); header.stringBlock = ( char *)FIX_ENDIAN_INT_32( ( udword )header.stringBlock ); header.length = FIX_ENDIAN_FLOAT_32( header.length ); header.framesPerSecond = FIX_ENDIAN_FLOAT_32( header.framesPerSecond ); header.nObjects = FIX_ENDIAN_INT_32( header.nObjects ); header.objPath = ( madobjpath *)FIX_ENDIAN_INT_32( ( udword )header.objPath ); header.nAnimations = FIX_ENDIAN_INT_32( header.nAnimations ); #endif #if MAD_ERROR_CHECKING if (strcmp(header.identifier, MAD_FileIdentifier) != 0) { dbgFatalf(DBG_Loc, "Invalid header in '%s'. Expected '%s', found '%s'.", fileName, MAD_FileIdentifier, header.identifier); } if (header.version != MAD_FileVersion) { dbgFatalf(DBG_Loc, "Invalid file version in '%s'. Expected %.2f, found %.2f", fileName, MAD_FileVersion, header.version); } if (header.nAnimations > MAD_MaxAnimations) { dbgFatalf(DBG_Loc, "Too many animations in '%s': %d", fileName, header.nAnimations); } #endif newHeader = memAlloc(fileSize - header.stringBlockLength, "meshAnimation", NonVolatile); *newHeader = header; fileBlockRead(file, &newHeader->anim[0], fileSize - newHeader->stringBlockLength - madHeaderSize(0)); newHeader->stringBlock = memAlloc(newHeader->stringBlockLength, "madStringBlock", NonVolatile);//!!!should this be non volatile? I guess it depends on how soon the string block is freed, if ever. fileBlockRead(file, newHeader->stringBlock, newHeader->stringBlockLength); fileClose(file); #if MAD_VERBOSE_LEVEL >= 2 dbgMessagef("madFileLoad: loaded %d animations for %d objects from '%s'", newHeader->nAnimations, newHeader->nObjects, fileName); #endif //loop through all the structures and fix up pointers for (index = 0; index < newHeader->nAnimations; index++) { //fixup the name of all animations #if FIX_ENDIAN newHeader->anim[index].name = ( char *)FIX_ENDIAN_INT_32( ( memsize )newHeader->anim[index].name ); newHeader->anim[index].startTime = FIX_ENDIAN_FLOAT_32( newHeader->anim[index].startTime ); newHeader->anim[index].endTime = FIX_ENDIAN_FLOAT_32( newHeader->anim[index].endTime ); newHeader->anim[index].flags = FIX_ENDIAN_INT_32( newHeader->anim[index].flags ); #endif newHeader->anim[index].name += (memsize)newHeader->stringBlock; } newHeader->objPath = (madobjpath *)((memsize)newHeader + (ubyte *)newHeader->objPath); for (index = 0; index < newHeader->nObjects; index++) { #if FIX_ENDIAN newHeader->objPath[index].name = ( char *)FIX_ENDIAN_INT_32( ( memsize )newHeader->objPath[index].name ); newHeader->objPath[index].nameCRC = FIX_ENDIAN_INT_16( newHeader->objPath[index].nameCRC ); newHeader->objPath[index].animationBits = FIX_ENDIAN_INT_32( newHeader->objPath[index].animationBits ); newHeader->objPath[index].nKeyframes = FIX_ENDIAN_INT_32( newHeader->objPath[index].nKeyframes ); newHeader->objPath[index].times = ( real32 *)FIX_ENDIAN_INT_32( ( udword )newHeader->objPath[index].times ); newHeader->objPath[index].parameters = ( tcb *)FIX_ENDIAN_INT_32( ( udword )newHeader->objPath[index].parameters ); #endif newHeader->objPath[index].name += (memsize)newHeader->stringBlock;//fixup name newHeader->objPath[index].nameCRC = crc16Compute((ubyte *)newHeader->objPath[index].name, strlen(newHeader->objPath[index].name)); newHeader->objPath[index].times = (real32 *)((memsize)newHeader + (ubyte *)newHeader->objPath[index].times);//fixup times pointers newHeader->objPath[index].parameters = (tcb *)((memsize)newHeader + (ubyte *)newHeader->objPath[index].parameters);//fixup times pointers for (j = 0; j < 6; j++) { //fixup the motion path array pointers #if FIX_ENDIAN newHeader->objPath[index].path[j] = ( real32 *)FIX_ENDIAN_INT_32( ( udword )newHeader->objPath[index].path[j] ); #endif newHeader->objPath[index].path[j] = (real32 *)((memsize)newHeader + (ubyte *)newHeader->objPath[index].path[j]); } #if FIX_ENDIAN for( j = 0; j < newHeader->objPath[index].nKeyframes; j++ ) { int k = 0; newHeader->objPath[index].times[j] = FIX_ENDIAN_FLOAT_32( newHeader->objPath[index].times[j] ); newHeader->objPath[index].parameters[j].tension = FIX_ENDIAN_FLOAT_32( newHeader->objPath[index].parameters[j].tension ); newHeader->objPath[index].parameters[j].continuity = FIX_ENDIAN_FLOAT_32( newHeader->objPath[index].parameters[j].continuity ); newHeader->objPath[index].parameters[j].bias = FIX_ENDIAN_FLOAT_32( newHeader->objPath[index].parameters[j].bias ); for( k = 0; k < 6; k++ ) { newHeader->objPath[index].path[k][j] = FIX_ENDIAN_FLOAT_32( newHeader->objPath[index].path[k][j] ); } } #endif } return(newHeader); }
/*----------------------------------------------------------------------------- Name : sdLabelListLoad Description : Load in a list of function pointers from a .MAP file. Inputs : mapFile - mapfile to load in Outputs : Return : ----------------------------------------------------------------------------*/ void sdLabelListLoad(char *mapFile) { char readLine[256]; char textSegmentString[10]; char *string, *label, *module; FILE *fp; sdword nScanned; udword textSegment = 0xffffffff; udword segment, base, length; sdfunctionlabel *newAlloc; fp = fopen(mapFile, "rt"); if (fp == NULL) { dbgFatalf(DBG_Loc, "Cannot open map file '%s'.", mapFile); } printf("\nLoading MAP file '%s'", mapFile); while (!feof(fp)) { if (!fgets(readLine, 255, fp)) { break; } if (sdNLabels >= sdNAllocated) { printf("."); sdNAllocated += SD_LabelListInc; newAlloc = memAlloc(sizeof(sdfunctionlabel) * sdNAllocated, "LabelList", 0); if (sdFunctions != NULL) { memcpy(newAlloc, sdFunctions, sizeof(sdfunctionlabel) * sdNAllocated); //memFree(sdFunctions); } sdFunctions = newAlloc; } if (strstr(readLine, " .text ") != NULL) { //definition of the code segment dbgAssert(strstr(readLine, "CODE")); dbgAssert(textSegment == 0xffffffff); nScanned = sscanf(readLine, "%x:%x %xH", &segment, &base, &length); dbgAssert(nScanned == 3); minFunctionAddress = base; maxFunctionAddress = base + length; textSegment = segment; dbgAssert(textSegment < 10); sprintf(textSegmentString, "000%d:", textSegment); } else { if (textSegment != 0xffffffff) { if ((string = strtok(readLine, " \t\n")) != NULL) { //found anything at all if (strstr(string, textSegmentString) == string) { //found segment/address nScanned = sscanf(string, "%x:%x", &segment, &base); if (nScanned == 2 && base >= minFunctionAddress && base <= maxFunctionAddress) { if ((string = strtok(NULL, " \t\n")) != NULL) { //found label label = string; if ((string = strtok(NULL, " \t\n")) != NULL) { //found preferred load address if ((string = strtok(NULL, " \t\n")) != NULL) { //found 'f' if ((string = strtok(NULL, " \t\n")) != NULL) { //found module name module = string; sdFunctions[sdNLabels].label = memAlloc(strlen(label) + strlen(module) + 2, "LabelModule", 0) strcpy(sdFunctions[sdNLabels].label, label); sdFunctions[sdNLabels].module = sdFunctions[sdNLabels].label + strlen(label) + 1; strcpy(sdFunctions[sdNLabels].module, module); sdFunctions[sdNLabels].address = base; sdNLabels++; } } } } } } } } } } if (textSegment == 0xffffffff || sdNLabels < 10) { dbgFatalf(DBG_Loc, "Could not load text segment from map file '%s'.", mapFile); } fclose(fp); }
/*----------------------------------------------------------------------------- Name : frFontRegister Description : Register usage of a font, loading it if needed Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ fonthandle frFontRegister(char *fileName) { sdword index, freeIndex = -1; char fullName[80]; for (index = FR_NumberFonts - 1; index >= 1; index--) { //for all of the registry if (frFontRegistry[index].name == NULL) { //if this one free freeIndex = index; } else { if (frNamesCompare(fileName, frFontRegistry[index].name)) { //if this is the font you want #if FR_VERBOSE_LEVEL >= 2 dbgMessagef("frFontRegister: Returning pre-registered font %s with usage count of %d", frFontRegistry[index].name, frFontRegistry[index].nUsageCount); #endif frFontRegistry[index].nUsageCount++; //increment usage count return(index); //return pre-loaded handle } } } #if FR_ERROR_CHECKING if (freeIndex == -1) { dbgFatalf(DBG_Loc, "Font registry not big enough for %s, only %d long", fileName, FR_NumberFonts); } #endif #if FR_VERBOSE_LEVEL >= 1 dbgMessagef("frFontRegister: Font %s not pre-registered, loading now...", fileName); #endif frFontRegistry[freeIndex].name = memStringDupe(fileName);//duplicate name string frFontRegistry[freeIndex].nUsageCount = 1; //start usage count at 1 strcpy(fullName, FR_PrependPath); //prepare file path if (strCurLanguage==languageEnglish) { strcat(fullName, FR_English); } else if (strCurLanguage==languageFrench) { strcat(fullName, FR_French); } else if (strCurLanguage==languageGerman) { strcat(fullName, FR_German); } else if (strCurLanguage==languageSpanish) { strcat(fullName, FR_Spanish); } else if (strCurLanguage==languageItalian) { strcat(fullName, FR_Italian); } strcat(fullName, fileName); frFontRegistry[freeIndex].fontdat = fontLoad(fullName); //load file frFontRegistry[freeIndex].handle = freeIndex; return(freeIndex); }