// // support code for the KAS language and its missions, FSMs, and states // // implementations of most functions are in kasfunc.c // #include #include #include "glinc.h" #include "mainrgn.h" #include "shipselect.h" #include "AITeam.h" #include "AIPlayer.h" #include "AIUtilities.h" #include "AIVar.h" #include "Timer.h" #include "vector.h" #include "kas.h" #include "file.h" #include "volume.h" #include "font.h" #include "render.h" #include "prim3d.h" #include "Objectives.h" #include "SinglePlayer.h" #include "SaveGame.h" #include "hs.h" #include "CommandWrap.h" extern sdword objectivesUsed; #if SP_DEBUGKEYS //#if SP_DEBUGLEVEL2 // for debug overlay extern fonthandle selGroupFont2; extern AIVar **vars; extern sdword varsUsed; extern sdword timersUsed; extern Timer *timers; sdword mrKASDebugDrawStates = FALSE; sdword mrKASDebugDrawTimers = FALSE; sdword mrKASDebugDrawVars = FALSE; sdword mrKASDebugDrawVolumes = FALSE; sdword mrKASSkipFactor = 0; #endif //SP_DEBUGLEVEL2 #define OBJECTIVES_COMPLETE_DELAY 10 // run-time scoping for variables, timers, etc. sdword CurrentMissionScope; // what level we're currently executing at char CurrentMissionScopeName[KAS_MISSION_NAME_MAX_LENGTH+1]; char CurrentMissionName[KAS_MISSION_NAME_MAX_LENGTH+1]; KASWatchFunction CurrentMissionWatchFunction = NULL; AITeam *CurrentTeamP = NULL; AITeam *kasUnpausedTeam = NULL; sdword CurrentMissionSkillLevel = 0; #define kasThisTeamPtr CurrentTeamP // // variable space for user selections (the labelled "SHIPS" type in KAS) // KasSelection **Selections = NULL; static sdword SelectionsUsed = 0; static sdword SelectionsAllocated = 0; // // table of labelled entities in mission layout file // (filled in at mission load time) // // team labels are stored in AITeam struct //LabelledAITeams *LabelledAITeam; //static sdword LabelledAITeamsUsed = 0; //static sdword LabelledAITeamsAllocated = 0; LabelledPath **LabelledPaths = NULL; static sdword LabelledPathsUsed = 0; static sdword LabelledPathsAllocated = 0; LabelledVector **LabelledVectors = NULL; sdword LabelledVectorsUsed = 0; sdword LabelledVectorsAllocated = 0; LabelledVolume **LabelledVolumes = NULL; static sdword LabelledVolumesUsed = 0; static sdword LabelledVolumesAllocated = 0; real32 subMessageReturnedFalseTime = 0; // need some closing stuff for kas - global variables need to be // made NULL etc. void kasClose() { kasUnpausedTeam = NULL; subMessageReturnedFalseTime = 0.0f; } void kasInit() { subMessageReturnedFalseTime = 0.0f; } void kasTeamDied(struct AITeam *team) { if (CurrentTeamP == team) { CurrentTeamP = NULL; } } // // JUMP keyword of KAS language // // sets state of current team to new state (for subsequently WATCHing) and executes its // init function right now // void kasJump(char *stateName, KASInitFunction initFunction, KASWatchFunction watchFunction) { #ifndef HW_Release { char teamName[KAS_TEAM_NAME_MAX_LENGTH+1]; aiplayerLog((aiCurrentAIPlayer->player->playerIndex,"KAS: TEAM(\"%s\") JUMP %s", kasAITeamName(CurrentTeamP, teamName), stateName)); } #endif memStrncpy(CurrentTeamP->kasStateName, stateName, KAS_STATE_NAME_MAX_LENGTH); CurrentTeamP->kasStateWatchFunction = watchFunction; initFunction(); } // // FSMCreate keyword of KAS language // // "creates" an FSM and hands control of a team to it // void kasFSMCreate(char *fsmName, KASInitFunction initFunction, KASWatchFunction watchFunction, AITeam *teamP) { AITeam *saveP; sdword saveScope; char SaveMissionScopeName[KAS_MISSION_NAME_MAX_LENGTH+1]; // save current team & scope saveP = CurrentTeamP; saveScope = CurrentMissionScope; strcpy(SaveMissionScopeName, CurrentMissionScopeName); CurrentTeamP = teamP; #ifndef HW_Release { char teamName[KAS_TEAM_NAME_MAX_LENGTH+1]; aiplayerLog((aiCurrentAIPlayer->player->playerIndex,"\nKAS: FSMCreate(\"%s\", TEAM(\"%s\")", fsmName, kasAITeamName(teamP, teamName))); } #endif teamP->teamType = ScriptTeam; memStrncpy(teamP->kasFSMName, fsmName, KAS_FSM_NAME_MAX_LENGTH); teamP->kasFSMWatchFunction = watchFunction; teamP->kasStateWatchFunction = NULL; // just in case it doesn't get set later teamP->kasTactics = Neutral; // default to neutral tactics teamP->kasFormation = NO_FORMATION; // default to no formation strcpy(CurrentMissionScopeName, kasThisTeamPtr->kasLabel); initFunction(); // restore current team & scope CurrentTeamP = saveP; CurrentMissionScope = saveScope; strcpy(CurrentMissionScopeName, SaveMissionScopeName); } // // all the processing of KAS controlled stuff happens here // // must be called once per AI cycle // void kasExecute(void) { sdword i; // no current mission? if (!CurrentMissionName[0] || !CurrentMissionWatchFunction) return; // watch for all objectives (if >= 1 defined) completed #if 0 if (timTimerExpiredDestroy("ObjectivesComplete")) kasfMissionCompleted(); else if (!timTimerRemaining("ObjectivesComplete") && objectivesUsed && objectiveGetAll()) timTimerCreateSetStart("ObjectivesComplete", OBJECTIVES_COMPLETE_DELAY); #endif if (kasUnpausedTeam == NULL) { //if KAS is not paused CurrentMissionWatchFunction(); // watch at the mission level for (i = 0; i < aiCurrentAIPlayer->teamsUsed; i++) { CurrentTeamP = aiCurrentAIPlayer->teams[i]; if (CurrentTeamP->teamType == ScriptTeam) { if (CurrentTeamP->kasFSMWatchFunction) // watch at the FSM level CurrentTeamP->kasFSMWatchFunction(); if (CurrentTeamP->kasStateWatchFunction) // watch at the state level CurrentTeamP->kasStateWatchFunction(); } } } else { //else all FSM's but one are paused CurrentTeamP = kasUnpausedTeam; //only execute this 1 unpaused team if (CurrentTeamP->teamType == ScriptTeam) { if (CurrentTeamP->kasFSMWatchFunction) // watch at the FSM level CurrentTeamP->kasFSMWatchFunction(); if (CurrentTeamP->kasStateWatchFunction) // watch at the state level CurrentTeamP->kasStateWatchFunction(); } } } // // starts a mission // void kasMissionStart(char *name, KASInitFunction initFunction, KASWatchFunction watchFunction) { aiplayerLog((0,"\nKAS: Starting %s", name)); memStrncpy(CurrentMissionName, name, KAS_MISSION_NAME_MAX_LENGTH); CurrentMissionWatchFunction = watchFunction; //hyperspace init hsStaticInit(LabelledVectorsUsed); initFunction(); // must go last - save game is called at end of this function, we want everything setup } // // return reference to labelled team // AITeam *kasAITeamPtr(char *label) { sdword i = 0; AITeam *aiteamp = NULL; while (i < aiCurrentAIPlayer->teamsUsed) { aiteamp = aiCurrentAIPlayer->teams[i]; if (aiteamp->teamType == ScriptTeam && !strnicmp(aiteamp->kasLabel, label, KAS_TEAM_NAME_MAX_LENGTH)) return aiteamp; ++i; } // special reference to sender of last message received if (!stricmp(label, "MsgSender")) return CurrentTeamP->msgSender; #ifndef HW_Release dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to team %s", label); #endif return NULL; } // // return reference to labelled team's ships (contrast with kasAITeamPtr) // GrowSelection *kasAITeamShipsPtr(char *label) { sdword i = 0; AITeam *aiteamp; while (i < aiCurrentAIPlayer->teamsUsed) { aiteamp = aiCurrentAIPlayer->teams[i]; if (aiteamp->teamType == ScriptTeam && !strnicmp(aiteamp->kasLabel, label, KAS_TEAM_NAME_MAX_LENGTH)) return &aiteamp->shipList; ++i; } // special reference to sender of last message received if (!stricmp(label, "MsgSender")) if (CurrentTeamP->msgSender) return &CurrentTeamP->msgSender->shipList; #ifndef HW_Release dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to team %s", label); #endif return NULL; } // // return reference to labelled grow selection's vector // hvector *kasShipsVectorPtr(char *label) { static hvector errorPos= {0, 0, 0, 1}; // safe fallback static hvector location; vector loc; sdword i = 0; GrowSelection *grow; real32 dummy; grow = kasGetGrowSelectionPtrIfExists(label); if (grow && grow->selection->numShips) { loc = selCentrePointComputeGeneral((MaxSelection *)grow->selection, &dummy); vecMakeHVecFromVec(location, loc); return &location; } else { return &errorPos; } #ifndef HW_Release dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to shiplist %s", label); #endif return NULL; } // // return reference to labelled team's location // hvector *kasTeamsVectorPtr(char *label) { static hvector errorPos = {0,0,0,1}; static hvector location; vector loc; GrowSelection *grow; real32 dummy; grow = kasAITeamShipsPtr(label); if (grow && grow->selection->numShips) { loc = selCentrePointComputeGeneral((MaxSelection *)grow->selection, &dummy); vecMakeHVecFromVec(location, loc); return &location; } else { return &errorPos; } #ifndef HW_Release dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to shiplist %s", label); #endif return NULL; } // // return reference to labelled volume's center // hvector *kasVolumeVectorPtr(char *label) { static hvector returnhvec; vector volcenter; Volume *vol = kasVolumePtr(label); if (vol) { volcenter = volFindCenter(vol); vecMakeHVecFromVec(returnhvec, volcenter); return &returnhvec; } else { return NULL; } } // // return reference to the team's centerpoint // hvector *kasThisTeamsVectorPtr(void) { static hvector errorPos = {0,0,0,1}; static hvector location; vector loc; GrowSelection *grow; real32 dummy; grow = &CurrentTeamP->shipList; if (grow && grow->selection->numShips) { loc = selCentrePointComputeGeneral((MaxSelection *)grow->selection, &dummy); vecMakeHVecFromVec(location, loc); return &location; } else { return &errorPos; } #ifndef HW_Release dbgFatalf(DBG_Loc,"\nKAS: unresolved reference in kasThisTeamsVectorPtr"); #endif return NULL; } // // return reference to labelled path // Path *kasPathPtrNoErrorChecking(char *label) { sdword i = 0; while (i < LabelledPathsUsed) { if (!strnicmp(LabelledPaths[i]->label, label, KAS_MAX_LABEL_LENGTH)) return LabelledPaths[i]->path; ++i; } return NULL; } // // return reference to labelled path // Path *kasPathPtr(char *label) { sdword i = 0; while (i < LabelledPathsUsed) { if (!strnicmp(LabelledPaths[i]->label, label, KAS_MAX_LABEL_LENGTH)) return LabelledPaths[i]->path; ++i; } dbgMessagef("\nKAS: unresolved reference to path %s", label); dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to path %s", label); // deliberately crash so designers can find bug easier return NULL; } // // return reference to labelled volume // Volume *kasVolumePtr(char *label) { sdword i = 0; while (i < LabelledVolumesUsed) { if (!strnicmp(LabelledVolumes[i]->label, label, KAS_MAX_LABEL_LENGTH)) return LabelledVolumes[i]->volume; ++i; } #ifndef HW_Release dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to volume %s", label); #endif return NULL; } // // return reference to labelled point // hvector *kasVectorPtrIfExists(char *label) { sdword i = 0; while (i < LabelledVectorsUsed) { if (!strnicmp(LabelledVectors[i]->label, label, KAS_MAX_LABEL_LENGTH)) return LabelledVectors[i]->hvector; ++i; } return NULL; } hvector *kasVectorPtr(char *label) { hvector *vec = kasVectorPtrIfExists(label); #ifndef HW_Release if (label == NULL) { dbgFatalf(DBG_Loc,"\nKAS: unresolved reference to point %s", label); } #endif return vec; } GrowSelection *kasGetGrowSelectionPtrIfExists(char *label) { sdword i = 0; while (i < SelectionsUsed) { if (!strnicmp(Selections[i]->label, label, KAS_MAX_LABEL_LENGTH)) return &(Selections[i]->shipList); ++i; } return NULL; } // // on first reference to a new GrowSelection, create one and return its pointer // otherwise, return the pointer // GrowSelection *kasGrowSelectionPtr(char *label) { sdword i = 0; while (i < SelectionsUsed) { if (!strnicmp(Selections[i]->label, label, KAS_MAX_LABEL_LENGTH)) return &(Selections[i]->shipList); ++i; } if (!Selections) { Selections = memAlloc(sizeof(KasSelection *) * KASSELECTION_ALLOC_INCREMENT, "kasSelections", 0); SelectionsAllocated = KASSELECTION_ALLOC_INCREMENT; SelectionsUsed = 0; } // keep track of all allocations if (SelectionsUsed >= SelectionsAllocated) { // allocate more if necessary Selections = memRealloc(Selections, sizeof(KasSelection *) * (SelectionsAllocated + KASSELECTION_ALLOC_INCREMENT), "kasSelections", 0); SelectionsAllocated += KASSELECTION_ALLOC_INCREMENT; } Selections[SelectionsUsed] = memAlloc(sizeof(KasSelection), "kasGrowSelection", 0); memStrncpy(Selections[SelectionsUsed]->label, label, KAS_MAX_LABEL_LENGTH); growSelectInit(&Selections[SelectionsUsed]->shipList); return &(Selections[SelectionsUsed++]->shipList); } void kasGrowSelectionClear(GrowSelection *ships) { if (ships && ships->selection) { ships->selection->numShips = 0; } } // // add new labelled path (with no points, yet), return pointer to it // Path *kasLabelledPathAdd(char *label, sdword numPoints, sdword closed) { if (!LabelledPaths) { LabelledPaths = memAlloc(sizeof(LabelledPath *) * KAS_LABELLED_ENTITY_ALLOC_INCREMENT, "kasLabelledPaths", 0); LabelledPathsAllocated = KAS_LABELLED_ENTITY_ALLOC_INCREMENT; LabelledPathsUsed = 0; } // keep track of all allocations if (LabelledPathsUsed >= LabelledPathsAllocated) { // allocate more if necessary LabelledPaths = memRealloc(LabelledPaths, sizeof(LabelledPath *) * (LabelledPathsAllocated + KAS_LABELLED_ENTITY_ALLOC_INCREMENT), "kasLabelledPaths", 0); LabelledPathsAllocated += KAS_LABELLED_ENTITY_ALLOC_INCREMENT; } LabelledPaths[LabelledPathsUsed] = memAlloc(sizeof(LabelledPath), "kasLabelledPath", MBF_NonVolatile); LabelledPaths[LabelledPathsUsed]->path = aiuCreatePathStruct(numPoints, closed); memStrncpy(LabelledPaths[LabelledPathsUsed]->label, label, KAS_MAX_LABEL_LENGTH); return LabelledPaths[LabelledPathsUsed++]->path; } // // add new labelled volume (with no contents, yet), return pointer to it // Volume *kasLabelledVolumeAdd(char *label) { if (!LabelledVolumes) { LabelledVolumes = memAlloc(sizeof(LabelledVolume *) * KAS_LABELLED_ENTITY_ALLOC_INCREMENT, "kasLabelledVolumes", 0); LabelledVolumesAllocated = KAS_LABELLED_ENTITY_ALLOC_INCREMENT; LabelledVolumesUsed = 0; } // keep track of all allocations if (LabelledVolumesUsed >= LabelledVolumesAllocated) { // allocate more if necessary LabelledVolumes = memRealloc(LabelledVolumes, sizeof(LabelledVolume *) * (LabelledVolumesAllocated + KAS_LABELLED_ENTITY_ALLOC_INCREMENT), "kasLabelledVolumes", 0); LabelledVolumesAllocated += KAS_LABELLED_ENTITY_ALLOC_INCREMENT; } LabelledVolumes[LabelledVolumesUsed] = memAlloc(sizeof(LabelledVolume), "kasLabelledVolume", MBF_NonVolatile); LabelledVolumes[LabelledVolumesUsed]->volume = memAlloc(sizeof(Volume), "kasVolume", MBF_NonVolatile); memStrncpy(LabelledVolumes[LabelledVolumesUsed]->label, label, KAS_MAX_LABEL_LENGTH); return LabelledVolumes[LabelledVolumesUsed++]->volume; } // // add new labelled vector, return pointer to it // hvector *kasLabelledVectorAdd(char *label, real32 x, real32 y, real32 z, real32 w) { if (!LabelledVectors) { LabelledVectors = memAlloc(sizeof(LabelledVector *) * KAS_LABELLED_ENTITY_ALLOC_INCREMENT, "kasLabelledVectors", 0); LabelledVectorsAllocated = KAS_LABELLED_ENTITY_ALLOC_INCREMENT; LabelledVectorsUsed = 0; } // keep track of all allocations if (LabelledVectorsUsed >= LabelledVectorsAllocated) { // allocate more if necessary LabelledVectors = memRealloc(LabelledVectors, sizeof(LabelledVector *) * (LabelledVectorsAllocated + KAS_LABELLED_ENTITY_ALLOC_INCREMENT), "kasLabelledVectors", 0); LabelledVectorsAllocated += KAS_LABELLED_ENTITY_ALLOC_INCREMENT; } LabelledVectors[LabelledVectorsUsed] = memAlloc(sizeof(LabelledVector), "kasLabelledVector", MBF_NonVolatile); LabelledVectors[LabelledVectorsUsed]->hvector = memAlloc(sizeof(hvector), "kasVector", MBF_NonVolatile); memStrncpy(LabelledVectors[LabelledVectorsUsed]->label, label, KAS_MAX_LABEL_LENGTH); LabelledVectors[LabelledVectorsUsed]->hvector->x = x; LabelledVectors[LabelledVectorsUsed]->hvector->y = y; LabelledVectors[LabelledVectorsUsed]->hvector->z = z; LabelledVectors[LabelledVectorsUsed]->hvector->w = w; return LabelledVectors[LabelledVectorsUsed++]->hvector; } // // remove all labelled entities // void kasLabelledEntitiesDestroy(void) { sdword i; CurrentTeamP = NULL; // selections for (i = 0; i < SelectionsUsed; ++i) { growSelectClose(&Selections[i]->shipList); memFree(Selections[i]); } if (Selections) memFree(Selections); SelectionsUsed = 0; SelectionsAllocated = 0; Selections = NULL; // vectors for (i = 0; i < LabelledVectorsUsed; ++i) { memFree(LabelledVectors[i]->hvector); memFree(LabelledVectors[i]); } if (LabelledVectors) memFree(LabelledVectors); LabelledVectorsUsed = 0; LabelledVectorsAllocated = 0; LabelledVectors = NULL; // volumes for (i = 0; i < LabelledVolumesUsed; ++i) { memFree(LabelledVolumes[i]->volume); memFree(LabelledVolumes[i]); } if (LabelledVolumes) memFree(LabelledVolumes); LabelledVolumesUsed = 0; LabelledVolumesAllocated = 0; LabelledVolumes = NULL; // paths for (i = 0; i < LabelledPathsUsed; ++i) { memFree(LabelledPaths[i]->path); memFree(LabelledPaths[i]); } if (LabelledPaths) memFree(LabelledPaths); LabelledPathsUsed = 0; LabelledPathsAllocated = 0; LabelledPaths = NULL; // vars aivarDestroyAll(); // timers timTimerDestroyAll(); } // // Find team label from pointer. // Returns teamName (& fills it in). // If not found, returns "NULL" or something like that. // char *kasAITeamName(AITeam *team, char *teamName) { if (team) strcpy(teamName, team->kasLabel); else strcpy(teamName, "NULL"); return teamName; } /*----------------------------------------------------------------------------- Name : kasAddShipToTeam Description : utility function to add a ship to a team (creates team if doesn't exist) Inputs : ship, str Outputs : Return : ----------------------------------------------------------------------------*/ void kasAddShipToTeam(Ship *ship,char *label) { sdword i; AITeam *teamp; // if labelled team doesn't currently exist, create it // otherwise, add ships to existing labelled team for (i = 0; i < aiCurrentAIPlayer->teamsUsed; i++) { teamp = aiCurrentAIPlayer->teams[i]; if (teamp->teamType == ScriptTeam && !strnicmp(teamp->kasLabel, label, KAS_TEAM_NAME_MAX_LENGTH)) break; } if (i >= aiCurrentAIPlayer->teamsUsed) { teamp = aitCreate(ScriptTeam); memStrncpy(teamp->kasLabel, label, KAS_TEAM_NAME_MAX_LENGTH); teamp->kasOrigShipsCount = 0; } teamp->kasOrigShipsCount++; teamp->kasOrigShipsType = ship->shiptype; aitAddShip(teamp, ship); teamp->newships--; } // // remove ship reference from any ship lists // void kasShipDied(Ship *ship) { sdword i = 0; while (i < SelectionsUsed) { clRemoveShipFromSelection(Selections[i]->shipList.selection, ship); ++i; } } // // wipe the labelled object tables clean // (do this before reading in a new mission layout) // void kasLabelsInit(void) { LabelledPathsUsed = 0; LabelledVectorsUsed = 0; LabelledVolumesUsed = 0; //hyperspace reset hsStaticReset(); } ////////////////////////////////////////////////////////////////// //Encase all this debug stuff in this ifdef // // this macro takes care of column wrapping // for the debug display // #define COLUMN_CHECK \ if (y > MAIN_WindowHeight - 2*rowHeight) \ { \ y = rowHeight; \ x += MAIN_WindowWidth/2 - rowHeight; \ } #if SP_DEBUGKEYS /*----------------------------------------------------------------------------- Name : kasTakeADump Description : Dumps all the singleplayer information into a file Inputs : None Outputs : A brand new file! Return : void ----------------------------------------------------------------------------*/ void kasTakeADump(void) { FILE *fp; char fileName[256] = "StatusDump.txt", *fullName; udword i, remaining; Timer *tp; fullName = filePathPrepend(fileName, 0); fp = fopen(fullName, "wt"); fprintf(fp, "%s\n\n", CurrentMissionName); //printout states fprintf(fp, "STATES:\n"); for (i=0;iteamsUsed;i++) { CurrentTeamP = aiCurrentAIPlayer->teams[i]; if (CurrentTeamP->teamType == ScriptTeam) { fprintf(fp, "%s {%d} : %s %s\n", CurrentTeamP->kasLabel, CurrentTeamP->shipList.selection->numShips, CurrentTeamP->kasFSMName, CurrentTeamP->kasStateName); } } //printout variables fprintf(fp, "\nVARIABLES:\n"); for (i = 0; i < varsUsed; ++i) { if (vars[i]->label[0] != '_' && vars[i]->label[1] != 'V') // skip non KAS vars { fprintf(fp, "%s = %d\n", vars[i]->label, vars[i]->value); } } //printout timers fprintf(fp, "\nTIMERS:\n"); for (i=0;iduration - (universe.totaltimeelapsed - tp->startTime)); if (remaining <= 0) { fprintf(fp, "%s EXPIRED\n", tp->name); } else { fprintf(fp, "%s %s : %ds\n", tp->name, tp->enabled ? "ON" : "OFF", remaining); } } fclose(fp); clCommandMessage("Taking a Dump"); } /*----------------------------------------------------------------------------- Name : kasCountDisplayLines Description : Counts the number of lines the debug draw routine will be drawing Inputs : none Outputs : none Return : Returns the number of lines to draw ----------------------------------------------------------------------------*/ udword kasCountDisplayLines(udword *states, udword *variables) { udword display = 0, i=0; *states = 0; *variables = 0; //count the number of states to draw if (mrKASDebugDrawStates) { for (i=0; iteamsUsed;i++) { if (aiCurrentAIPlayer->teams[i]->teamType == ScriptTeam) { display++; *states++; } } } //count the number of Variables to draw if (mrKASDebugDrawVars) { for (i=0; ilabel[0] != '_' && vars[i]->label[1] != 'V') { display++; *variables++; } } } //count the number of Timers to draw if (mrKASDebugDrawTimers) { display += timersUsed; } return display; } #define KAS_NUM_SCREEN_LINES 80 void kasDebugDraw(void) { sdword rowHeight, y, x, i; // fonthandle fhSave; AITeam *CurrentTeamP; sdword remaining; Timer *tp; char buf[256]; vector vec0, vec1; Volume *volumep; udword numlines = 0, numstates = 0, numvars = 0, skiplines = 0; if (!gameIsRunning) return; if (!CurrentMissionName[0] || !CurrentMissionWatchFunction) return; // set up textual stuff // fhSave = fontCurrentGet(); //save the current font // fontMakeCurrent(selGroupFont2); // use a common, fairly small font rowHeight = fontHeight("M")-2; // used to space the text y = rowHeight; x = (sdword)rowHeight; #if SP_DEBUGLEVEL2 //count the number of lines to display numlines = kasCountDisplayLines(&numstates, &numvars); skiplines = mrKASSkipFactor*KAS_NUM_SCREEN_LINES; // if we're displaying less than the screen can hold, // or if the user has paged over if ((numlines < KAS_NUM_SCREEN_LINES) || (numlines < skiplines)) { skiplines = 0; mrKASSkipFactor = 0; } // states if (mrKASDebugDrawStates) { // mission name fontPrint(x-rowHeight/2, y + (rowHeight>>2), KAS_DEBUG_TEXTCOLOR, CurrentMissionName); y += rowHeight + 1; COLUMN_CHECK // each team's state for (i = 0; i < aiCurrentAIPlayer->teamsUsed; i++) { CurrentTeamP = aiCurrentAIPlayer->teams[i]; if (CurrentTeamP->teamType == ScriptTeam) { if (skiplines) { skiplines--; } else { sprintf(buf, "%s {%d} : %s %s", CurrentTeamP->kasLabel, CurrentTeamP->shipList.selection->numShips, CurrentTeamP->kasFSMName, CurrentTeamP->kasStateName); fontPrint(x, y + (rowHeight>>2), KAS_DEBUG_TEXTCOLOR, buf); y += rowHeight + 1; COLUMN_CHECK } } } y += rowHeight/3; COLUMN_CHECK } // vars if (mrKASDebugDrawVars) { sprintf(buf,"Enemy RU = %d",universe.players[1].resourceUnits); fontPrint(x, y + (rowHeight>>2), KAS_DEBUG_TEXTCOLOR, buf); y += rowHeight + 1; COLUMN_CHECK for (i = 0; i < varsUsed; ++i) { if (vars[i]->label[0] != '_' && vars[i]->label[1] != 'V') // skip non KAS vars { if (skiplines) { skiplines--; } else { sprintf(buf, "%s = %d", vars[i]->label, vars[i]->value); fontPrint(x, y + (rowHeight>>2), KAS_DEBUG_TEXTCOLOR, buf); y += rowHeight + 1; COLUMN_CHECK } } } y += rowHeight/3; COLUMN_CHECK } // timers if (mrKASDebugDrawTimers) { for (i = 0; i < timersUsed; ++i) { if (skiplines) { skiplines--; } else { tp = &timers[i]; remaining = (sdword)(tp->duration - (universe.totaltimeelapsed - tp->startTime)); if (remaining <= 0) sprintf(buf, "%s EXPIRED", tp->name); else sprintf(buf, "%s %s : %ds", tp->name, tp->enabled ? "ON" : "OFF", remaining); fontPrint(x, y + (rowHeight>>2), KAS_DEBUG_TEXTCOLOR, buf); y += rowHeight + 1; COLUMN_CHECK } } y += rowHeight/3; COLUMN_CHECK } // volumes if (mrKASDebugDrawVolumes) { primModeClear2(); rndLightingEnable(FALSE); rndTextureEnable(FALSE); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); rgluPerspective(mrCamera->fieldofview, rndAspectRatio, mrCamera->clipPlaneNear, mrCamera->clipPlaneFar * 15.0f); glMatrixMode(GL_MODELVIEW); #if 0 { Ship *m0p = aiuFindEnemyMothership(&universe.players[0]), *m1p = aiuFindEnemyMothership(&universe.players[1]); primCircleOutline3(&m0p->posinfo.position, 10000, 32, 4, KAS_DEBUG_TEXTCOLOR, X_AXIS); primCircleOutline3(&m0p->posinfo.position, 10000, 32, 4, KAS_DEBUG_TEXTCOLOR, Y_AXIS); primCircleOutline3(&m0p->posinfo.position, 10000, 32, 8, KAS_DEBUG_TEXTCOLOR, Z_AXIS); primCircleOutline3(&m1p->posinfo.position, 10000, 32, 0, KAS_DEBUG_TEXTCOLOR, X_AXIS); primCircleOutline3(&m1p->posinfo.position, 10000, 32, 0, KAS_DEBUG_TEXTCOLOR, Y_AXIS); primCircleOutline3(&m1p->posinfo.position, 10000, 32, 8, KAS_DEBUG_TEXTCOLOR, Z_AXIS); } #endif for (i = 0; i < LabelledVolumesUsed; ++i) { volumep = LabelledVolumes[i]->volume; switch (volumep->type) { case VOLUME_AA_BOX: vec0.x = volumep->attribs.aaBox.x0; vec1.x = volumep->attribs.aaBox.x1; vec0.y = volumep->attribs.aaBox.y0; vec1.y = volumep->attribs.aaBox.y0; vec0.z = volumep->attribs.aaBox.z0; vec1.z = volumep->attribs.aaBox.z0; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x1; vec0.y = volumep->attribs.aaBox.y1; vec0.z = volumep->attribs.aaBox.z0; primLine3(&vec1, &vec0, KAS_DEBUG_TEXTCOLOR); vec1.x = volumep->attribs.aaBox.x0; vec1.y = volumep->attribs.aaBox.y1; vec1.z = volumep->attribs.aaBox.z0; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x0; vec0.y = volumep->attribs.aaBox.y0; vec0.z = volumep->attribs.aaBox.z0; primLine3(&vec1, &vec0, KAS_DEBUG_TEXTCOLOR); vec1.x = volumep->attribs.aaBox.x0; vec1.y = volumep->attribs.aaBox.y0; vec1.z = volumep->attribs.aaBox.z1; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x1; vec0.y = volumep->attribs.aaBox.y0; vec0.z = volumep->attribs.aaBox.z1; primLine3(&vec1, &vec0, KAS_DEBUG_TEXTCOLOR); vec1.x = volumep->attribs.aaBox.x1; vec1.y = volumep->attribs.aaBox.y1; vec1.z = volumep->attribs.aaBox.z1; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x0; vec0.y = volumep->attribs.aaBox.y1; vec0.z = volumep->attribs.aaBox.z1; primLine3(&vec1, &vec0, KAS_DEBUG_TEXTCOLOR); vec1.x = volumep->attribs.aaBox.x0; vec1.y = volumep->attribs.aaBox.y0; vec1.z = volumep->attribs.aaBox.z1; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x0; vec1.x = volumep->attribs.aaBox.x0; vec0.y = volumep->attribs.aaBox.y1; vec1.y = volumep->attribs.aaBox.y1; vec0.z = volumep->attribs.aaBox.z0; vec1.z = volumep->attribs.aaBox.z1; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x1; vec1.x = volumep->attribs.aaBox.x1; vec0.y = volumep->attribs.aaBox.y1; vec1.y = volumep->attribs.aaBox.y1; vec0.z = volumep->attribs.aaBox.z0; vec1.z = volumep->attribs.aaBox.z1; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); vec0.x = volumep->attribs.aaBox.x1; vec1.x = volumep->attribs.aaBox.x1; vec0.y = volumep->attribs.aaBox.y0; vec1.y = volumep->attribs.aaBox.y0; vec0.z = volumep->attribs.aaBox.z0; vec1.z = volumep->attribs.aaBox.z1; primLine3(&vec0, &vec1, KAS_DEBUG_TEXTCOLOR); break; case VOLUME_SPHERE: primCircleOutline3(&volumep->attribs.sphere.center, volumep->attribs.sphere.radius, 32, 4, KAS_DEBUG_TEXTCOLOR, X_AXIS); primCircleOutline3(&volumep->attribs.sphere.center, volumep->attribs.sphere.radius, 32, 4, KAS_DEBUG_TEXTCOLOR, Y_AXIS); primCircleOutline3(&volumep->attribs.sphere.center, volumep->attribs.sphere.radius, 32, 4, KAS_DEBUG_TEXTCOLOR, Z_AXIS); break; } } glMatrixMode(GL_PROJECTION); glLoadMatrixf((GLfloat*)&rndProjectionMatrix); glMatrixMode(GL_MODELVIEW); primModeSet2(); } #endif //SP_DEBUGLEVEL2 // fontMakeCurrent(fhSave); } #endif //SP_DEBUGKEYS /*============================================================================= Save Game Stuff =============================================================================*/ void SaveKasSelection(KasSelection *kasselection) { SaveStructureOfSize(kasselection,sizeof(KasSelection)); SaveGrowSelection(&kasselection->shipList); } KasSelection *LoadKasSelection() { KasSelection *kasselection = LoadStructureOfSize(sizeof(KasSelection)); LoadGrowSelectionAndFix(&kasselection->shipList); return kasselection; } void SaveLabelledPath(LabelledPath *labelledpath) { SaveStructureOfSize(labelledpath,sizeof(LabelledPath)); SavePath(labelledpath->path); } LabelledPath *LoadLabelledPath() { LabelledPath *labelledpath = LoadStructureOfSize(sizeof(LabelledPath)); labelledpath->path = LoadPath(); return labelledpath; } void SaveLabelledVector(LabelledVector *labelledvector) { SaveStructureOfSize(labelledvector,sizeof(LabelledVector)); SaveStructureOfSize(labelledvector->hvector,sizeof(hvector)); } LabelledVector *LoadLabelledVector() { LabelledVector *labelledvector = LoadStructureOfSize(sizeof(LabelledVector)); labelledvector->hvector = LoadStructureOfSize(sizeof(hvector)); return labelledvector; } void SaveLabelledVolume(LabelledVolume *labelledvolume) { SaveStructureOfSize(labelledvolume,sizeof(LabelledVolume)); SaveStructureOfSize(labelledvolume->volume,sizeof(Volume)); } LabelledVolume *LoadLabelledVolume() { LabelledVolume *labelledvolume = LoadStructureOfSize(sizeof(LabelledVolume)); labelledvolume->volume = LoadStructureOfSize(sizeof(Volume)); return labelledvolume; } void kasSave(void) { sdword i; // hyperspace save SaveHyperspaceGates(); // Save Global Variables SaveInfoNumber(CurrentMissionScope); SaveStructureOfSize(CurrentMissionScopeName,sizeof(CurrentMissionScopeName)); SaveStructureOfSize(CurrentMissionName,sizeof(CurrentMissionName)); SaveInfoNumber(WatchFunctionToIndex(CurrentMissionWatchFunction)); //this is a fix for a weird bug where after starting the game over and over //Current SaveInfoNumber(AITeamToTeamIndex(CurrentTeamP)); SaveInfoNumber(CurrentMissionSkillLevel); // Save Selections SaveInfoNumber(SelectionsUsed); SaveInfoNumber(SelectionsAllocated); for (i=0;i 0) { Selections = memAlloc(sizeof(KasSelection *)*SelectionsAllocated, "kasSelections", 0); } else { Selections = NULL; } for (i=0;i 0) { LabelledPaths = memAlloc(sizeof(LabelledPath *)*LabelledPathsAllocated, "kasLabelledPaths", 0); } else { LabelledPaths = NULL; } for (i=0;i 0) { LabelledVectors = memAlloc(sizeof(LabelledVector *)*LabelledVectorsAllocated, "kasLabelledVectors", 0); } else { LabelledVectors = NULL; } for (i=0;i 0) { LabelledVolumes = memAlloc(sizeof(LabelledVolume *)*LabelledVolumesAllocated, "kasLabelledVolumes", 0); } else { LabelledVolumes = NULL; } for (i=0;i