/* Tutor.c - Functions for the Tutorial System */ #include #include "glinc.h" #include #include #include #include #include "types.h" #include "feflow.h" #include "aiplayer.h" #include "utility.h" #include "levelload.h" #include "region.h" #include "KAS.h" #include "uicontrols.h" #include "strings.h" #include "fontreg.h" #include "select.h" #include "texreg.h" #include "fontReg.h" #include "render.h" #include "mouse.h" #include "fastmath.h" #include "Tutor.h" #include "Utility.h" #include "consmgr.h" #include "cameracommand.h" #include "fastmath.h" #include "savegame.h" #include "collision.h" #include "gamepick.h" #include "main.h" #include "subtitle.h" #include "singleplayer.h" #include "speechevent.h" #include "soundevent.h" #include "file.h" #include "mainrgn.h" #include "taskbar.h" #include "..\\Generated\\tutorial1.h" //hack to get the speech to work when game is paused bool FalkosFuckedUpTutorialFlag = FALSE; // Function declarations void utySinglePlayerGameStart(char *name, featom *atom); char *tutGetNextTextLine(char *pDest, char *pString, long Width); udword tutProcessNextButton(struct tagRegion *reg, sdword ID, udword event, udword data); udword tutProcessBackButton(struct tagRegion *reg, sdword ID, udword event, udword data); udword uicButtonProcess(regionhandle region, sdword ID, udword event, udword data); // flags for controlling game elements from the tutorial tutGameEnableFlags tutEnable; char tutBuildRestrict[TOTAL_STD_SHIPS]; char tutGameMessageList[16][256]; long tutGameMessageIndex = 0; ShipType tutFEContextMenuShipType; static char tutLastLessonName[256] = ""; static char tutCurrLessonName[256] = ""; static const sbyte ExpandY = 0; static const sbyte ExpandX = 1; /* sdword tutTextPointerType = 0; sdword tutPointerX, tutPointerY; rectangle tutPointerRegion; hvector tutPointerAIPoint; */ ShipPtr tutPointerShip; rectangle *tutPointerShipHealthRect; rectangle *tutPointerShipGroupRect; //list of named tutorial pointers static tutpointer tutPointer[TUT_NumberPointers]; bool tutPointersDrawnThisFrame = FALSE; static sdword tutTextPosX, tutTextPosY; static sdword tutTextSizeX, tutTextSizeY; static rectangle tutTextRect; static fonthandle tutTextFont = 0; static regionhandle tutRootRegion; static sdword tutRootRegionCount = 0; // visibility flag & region handle for the displayed text sdword tutTextVisible = FALSE; regionhandle tutTextRegion = NULL; void tutDrawTextFunction(regionhandle reg); // visibility flag & region handle for the displayed images sdword tutImageVisible = FALSE; regionhandle tutImageRegion = NULL; void tutDrawImageFunction(regionhandle reg); // visibility flag & region handle for the "next" button sdword tutNextVisible = FALSE; buttonhandle tutNextRegion = NULL; sdword tutNextButtonState = 0; void tutDrawNextButtonFunction(regionhandle reg); // visibility flag & region handle for the "back" button sdword tutBackVisible = FALSE; sdword tutPrevVisible = FALSE; buttonhandle tutBackRegion = NULL; void tutDrawBackButtonFunction(regionhandle reg); // List of image indices for the displayed images static char szImageIndexList[16]; // Construction manager exports extern shipavailable *cmShipsAvailable; extern LinkedList listofShipsInProgress; featom tutRootAtom = { "TutorialWrapper", // char *name; //optional name of control FAF_Function, // udword flags; //flags to control behavior 0, // udword status; //status flags for this atom, checked etc. FA_UserRegion, // ubyte type; //type of control (button, scroll bar, etc.) 0, // ubyte borderWidth; //width, in pixels, of the border 0, // uword tabstop; //denotes the tab ordering of UI controls 150, // color borderColor; //optional color of border 4, // color contentColor; //optional color of content 0,0, // sdword x; //-+ 0,0, // sdword y; // |>rectangle of region 640,0, // sdword width; // | 480,0, // sdword height; //-+ NULL, // ubyte *pData; //pointer to type-specific data NULL, // ubyte *attribs; //sound(button atom) or font(static text atom) reference 0, // char hotKeyModifiers; 0, // char hotKey[FE_NumberLanguages]; 0, // udword drawstyle[2]; 0, // void* region; 0 // udword pad[2]; }; featom tutTextAtom = { "TutorialText", // char *name; //optional name of control FAF_Function, // udword flags; //flags to control behavior 0, // udword status; //status flags for this atom, checked etc. FA_UserRegion, // ubyte type; //type of control (button, scroll bar, etc.) 0, // ubyte borderWidth; //width, in pixels, of the border 0, // uword tabstop; //denotes the tab ordering of UI controls 150, // color borderColor; //optional color of border 4, // color contentColor; //optional color of content 0,0, // sdword x; //-+ 0,0, // sdword y; // |>rectangle of region 0,0, // sdword width; // | 0,0, // sdword height; //-+ NULL, // ubyte *pData; //pointer to type-specific data NULL, // ubyte *attribs; //sound(button atom) or font(static text atom) reference 0, // char hotKeyModifiers; 0, // char hotKey[FE_NumberLanguages]; 0, // udword drawstyle[2]; 0, // void* region; 0 // udword pad[2]; }; featom tutImageAtom = { "TutorialImage", // char *name; //optional name of control FAF_Function, // udword flags; //flags to control behavior 0, // udword status; //status flags for this atom, checked etc. FA_UserRegion, // ubyte type; //type of control (button, scroll bar, etc.) 0, // ubyte borderWidth; //width, in pixels, of the border 0, // uword tabstop; //denotes the tab ordering of UI controls 150, // color borderColor; //optional color of border 4, // color contentColor; //optional color of content 0,0, // sdword x; //-+ 0,0, // sdword y; // |>rectangle of region 0,0, // sdword width; // | 0,0, // sdword height; //-+ NULL, // ubyte *pData; //pointer to type-specific data NULL, // ubyte *attribs; //sound(button atom) or font(static text atom) reference 0, // char hotKeyModifiers; 0, // char hotKey[FE_NumberLanguages]; 0, // udword drawstyle[2]; 0, // void* region; 0 // udword pad[2]; }; featom tutNextAtom = { "TutorialNext", // char *name; //optional name of control FAF_Function, // udword flags; //flags to control behavior 0, // udword status; //status flags for this atom, checked etc. FA_Button, // ubyte type; //type of control (button, scroll bar, etc.) 0, // ubyte borderWidth; //width, in pixels, of the border 0, // uword tabstop; //denotes the tab ordering of UI controls 150, // color borderColor; //optional color of border 4, // color contentColor; //optional color of content 0,0, // sdword x; //-+ 0,0, // sdword y; // |>rectangle of region 0,0, // sdword width; // | 0,0, // sdword height; //-+ NULL, // ubyte *pData; //pointer to type-specific data NULL, // ubyte *attribs; //sound(button atom) or font(static text atom) reference 0, // char hotKeyModifiers; 0, // char hotKey[FE_NumberLanguages]; 0, // udword drawstyle[2]; 0, // void* region; 0 // udword pad[2]; }; featom tutBackAtom = { "TutorialBack", // char *name; //optional name of control FAF_Function, // udword flags; //flags to control behavior 0, // udword status; //status flags for this atom, checked etc. FA_Button, // ubyte type; //type of control (button, scroll bar, etc.) 0, // ubyte borderWidth; //width, in pixels, of the border 0, // uword tabstop; //denotes the tab ordering of UI controls 150, // color borderColor; //optional color of border 4, // color contentColor; //optional color of content 0,0, // sdword x; //-+ 0,0, // sdword y; // |>rectangle of region 0,0, // sdword width; // | 0,0, // sdword height; //-+ NULL, // ubyte *pData; //pointer to type-specific data NULL, // ubyte *attribs; //sound(button atom) or font(static text atom) reference 0, // char hotKeyModifiers; 0, // char hotKey[FE_NumberLanguages]; 0, // udword drawstyle[2]; 0, // void* region; 0 // udword pad[2]; }; #define TUT_NUM_IMAGES 33 #define TUT_NEXT_ON 0 #define TUT_NEXT_OFF 1 #define TUT_NEXT_MOUSE 2 #define TUT_PREV_ON 3 #define TUT_PREV_OFF 4 #define TUT_PREV_MOUSE 5 #define TUT_REST_ON 6 #define TUT_REST_OFF 7 #define TUT_REST_MOUSE 8 char *tutImageList[TUT_NUM_IMAGES] = { "Tut_Next_On", "Tut_Next_Off", "Tut_Next_Mouse", "Tut_previous_on", "Tut_previous_off", "Tut_previous_mouse", "Tut_restart_on", "Tut_restart_off", "Tut_restart_mouse", "Tut_Rightclick", "Tut_Key_F", "Tut_Key_M", "Tut_Key_Shift", "Tut_Key_Ctrl", "Tut_Key_Alt", "Tut_Key_Space", "Tut_Key_Tab", "Tut_Mouse_ButtonR", "Tut_Mouse_ButtonR_MoveLRUD", "Tut_Mouse_ButtonR_MoveLR", "Tut_Mouse_ButtonR_MoveU", "Tut_Mouse_ButtonR_MoveD", "Tut_Mouse_ButtonLR_MoveUD", "Tut_Mouse_ButtonLR_MoveU", "Tut_Mouse_ButtonLR_MoveD", "Tut_Mouse_ButtonL", "Tut_Mouse_ButtonL_MoveLRUD", "Tut_Mouse_ButtonM", "Tut_Mouse_Middle_RollD", "Tut_Mouse_Middle_RollU", "Tut_Mouse_Middle_RollUD", "Tut_Mouse_Lbandbox", "" }; char *tutFrenchImageList[TUT_NUM_IMAGES] = { "Tut_fr_Next_On", "Tut_fr_Next_Off", "Tut_fr_Next_Mouse", "Tut_fr_previous_on", "Tut_fr_previous_off", "Tut_fr_previous_mouse", "Tut_fr_restart_on", "Tut_fr_restart_off", "Tut_fr_restart_mouse", "Tut_Rightclick", "Tut_Key_F", "Tut_Key_D", "Tut_fr_Key_Shift", "Tut_fr_Key_Ctrl", "Tut_Key_Alt", "Tut_fr_Key_Space", "Tut_Key_Tab", "Tut_Mouse_ButtonR", "Tut_Mouse_ButtonR_MoveLRUD", "Tut_Mouse_ButtonR_MoveLR", "Tut_Mouse_ButtonR_MoveU", "Tut_Mouse_ButtonR_MoveD", "Tut_Mouse_ButtonLR_MoveUD", "Tut_Mouse_ButtonLR_MoveU", "Tut_Mouse_ButtonLR_MoveD", "Tut_Mouse_ButtonL", "Tut_Mouse_ButtonL_MoveLRUD", "Tut_Mouse_ButtonM", "Tut_Mouse_Middle_RollD", "Tut_Mouse_Middle_RollU", "Tut_Mouse_Middle_RollUD", "Tut_Mouse_Lbandbox", "" }; char *tutGermanImageList[TUT_NUM_IMAGES] = { "Tut_ger_Next_On", "Tut_ger_Next_Off", "Tut_ger_Next_Mouse", "Tut_ger_previous_on", "Tut_ger_previous_off", "Tut_ger_previous_mouse", "Tut_ger_restart_on", "Tut_ger_restart_off", "Tut_ger_restart_mouse", "Tut_Rightclick", "Tut_Key_F", "Tut_Key_W", "Tut_ger_Key_Shift", "Tut_ger_Key_Ctrl", "Tut_Key_Alt", "Tut_ger_Key_Space", "Tut_Key_Tab", "Tut_Mouse_ButtonR", "Tut_Mouse_ButtonR_MoveLRUD", "Tut_Mouse_ButtonR_MoveLR", "Tut_Mouse_ButtonR_MoveU", "Tut_Mouse_ButtonR_MoveD", "Tut_Mouse_ButtonLR_MoveUD", "Tut_Mouse_ButtonLR_MoveU", "Tut_Mouse_ButtonLR_MoveD", "Tut_Mouse_ButtonL", "Tut_Mouse_ButtonL_MoveLRUD", "Tut_Mouse_ButtonM", "Tut_Mouse_Middle_RollD", "Tut_Mouse_Middle_RollU", "Tut_Mouse_Middle_RollUD", "Tut_Mouse_Lbandbox", "" }; char *tutSpanishImageList[TUT_NUM_IMAGES] = { "Tut_sp_Next_On", "Tut_sp_Next_Off", "Tut_sp_Next_Mouse", "Tut_sp_previous_on", "Tut_sp_previous_off", "Tut_sp_previous_mouse", "Tut_sp_restart_on", "Tut_sp_restart_off", "Tut_sp_restart_mouse", "Tut_Rightclick", "Tut_Key_F", "Tut_Key_D", "Tut_sp_Key_Shift", "Tut_Key_Ctrl", "Tut_Key_Alt", "Tut_sp_Key_Space", "Tut_Key_Tab", "Tut_Mouse_ButtonR", "Tut_Mouse_ButtonR_MoveLRUD", "Tut_Mouse_ButtonR_MoveLR", "Tut_Mouse_ButtonR_MoveU", "Tut_Mouse_ButtonR_MoveD", "Tut_Mouse_ButtonLR_MoveUD", "Tut_Mouse_ButtonLR_MoveU", "Tut_Mouse_ButtonLR_MoveD", "Tut_Mouse_ButtonL", "Tut_Mouse_ButtonL_MoveLRUD", "Tut_Mouse_ButtonM", "Tut_Mouse_Middle_RollD", "Tut_Mouse_Middle_RollU", "Tut_Mouse_Middle_RollUD", "Tut_Mouse_Lbandbox", "" }; char *tutItalianImageList[TUT_NUM_IMAGES] = { "Tut_it_Next_On", "Tut_it_Next_Off", "Tut_it_Next_Mouse", "Tut_it_previous_on", "Tut_it_previous_off", "Tut_it_previous_mouse", "Tut_it_restart_on", "Tut_it_restart_off", "Tut_it_restart_mouse", "Tut_Rightclick", "Tut_Key_F", "Tut_Key_M", "Tut_Key_Shift", "Tut_Key_Ctrl", "Tut_Key_Alt", "Tut_it_Key_Space", "Tut_Key_Tab", "Tut_Mouse_ButtonR", "Tut_Mouse_ButtonR_MoveLRUD", "Tut_Mouse_ButtonR_MoveLR", "Tut_Mouse_ButtonR_MoveU", "Tut_Mouse_ButtonR_MoveD", "Tut_Mouse_ButtonLR_MoveUD", "Tut_Mouse_ButtonLR_MoveU", "Tut_Mouse_ButtonLR_MoveD", "Tut_Mouse_ButtonL", "Tut_Mouse_ButtonL_MoveLRUD", "Tut_Mouse_ButtonM", "Tut_Mouse_Middle_RollD", "Tut_Mouse_Middle_RollU", "Tut_Mouse_Middle_RollUD", "Tut_Mouse_Lbandbox", "" }; // This string structure must match the tutGameEnableFlags struct char *tutGameEnableString[] = { "KASFrame", // FOR INTERAL USE ONLY "GameRunning", "BuildManager", "SensorsManager", "ResearchManager", "PauseGame", "Dock", "Formation", "Launch", "Move", "MoveIssue", "Attack", "Harvest", "CancelCommand", "Scuttle", "Retire", "ClickSelect", "BandSelect", "CancelSelect", "Special", "BuildBuildShips", "BuildPauseJobs", "BuildCancelJobs", "BuildClose", "BuildArrows", "SensorsClose", "ContextMenus", "ContextFormDelta", "ContextFormBroad", "ContextFormX", "ContextFormClaw", "ContextFormWall", "ContextFormSphere", "ContextFormCustom", "Evasive", "Neutral", "Agressive", "TaskbarOpen", "TaskbarClose", "ResearchSelectTech", "ResearchSelectLab", "ResearchResearch", "ResearchClearLab", "ResearchClose", "Focus", "FocusCancel", "MothershipFocus", "LaunchSelectShips", "LaunchLaunch", "LaunchLaunchAll", "LaunchClose", "" }; color tutTexture[TUT_NUM_IMAGES]; lifheader *tutImage[TUT_NUM_IMAGES]; static char *tutTutorialNames[4] = {"", "Tutorial1"}; void tutPreInitTutorial(char *dirfile, char *levelfile) { sprintf(dirfile, "Tutorials\\%s\\", tutTutorialNames[tutorial]); sprintf(levelfile, "%s.mission", tutTutorialNames[tutorial]); tutEnableEverything(); //perform a level pass to see what ships we need to load levelPreInit(dirfile, levelfile); } void tutInitTutorial(char *dirfile, char *levelfile) { levelInit(dirfile, levelfile); tutLastLessonName[0] = '\0'; tutCurrLessonName[0] = '\0'; switch(tutorial) { case 1: kasMissionStart("tutorial1", Init_Tutorial1, Watch_Tutorial1); break; } } void tutSaveLesson(sdword Num, char *pName) { collUpdateCollBlobs(); collUpdateObjsInCollBlobs(); strcpy(tutLastLessonName, tutCurrLessonName); sprintf(tutCurrLessonName, "%s%s", TutorialSavedGamesPath, pName); SaveGame(tutCurrLessonName); } static void SaveLong(sdword Val) { SaveStructureOfSize( &Val, 4 ); } static sdword LoadLong(void) { sdword Val; LoadStructureOfSizeToAddress( &Val, 4 ); return Val; } void tutSaveTutorialGame(void) { Save_String(tutCurrLessonName); Save_String(tutLastLessonName); SaveStructureOfSize( &tutEnable, sizeof(tutGameEnableFlags) ); SaveStructureOfSize( tutBuildRestrict, sizeof(tutBuildRestrict) ); SaveLong(tutTextPosX); SaveLong(tutTextPosY); SaveLong(tutTextSizeX); SaveLong(tutTextSizeY); SaveStructureOfSize( &tutTextRect, sizeof(rectangle) ); SaveLong(tutTextVisible); SaveLong(tutNextVisible); SaveLong(tutBackVisible); SaveLong(FalkosFuckedUpTutorialFlag); } void tutLoadTutorialGame(void) { sdword index; Load_StringToAddress(tutCurrLessonName); Load_StringToAddress(tutLastLessonName); LoadStructureOfSizeToAddress( &tutEnable, sizeof(tutGameEnableFlags) ); LoadStructureOfSizeToAddress( tutBuildRestrict, sizeof(tutBuildRestrict) ); tutTextPosX = LoadLong(); tutTextPosY = LoadLong(); tutTextSizeX = LoadLong(); tutTextSizeY = LoadLong(); LoadStructureOfSizeToAddress( &tutTextRect, sizeof(rectangle) ); tutTextVisible = LoadLong(); tutNextVisible = LoadLong(); tutBackVisible = LoadLong(); FalkosFuckedUpTutorialFlag = LoadLong(); tutGameMessageIndex = 0; tutNextButtonState = 0; //tutTextPointerType = 0; //clear out all the pointers for (index = 0; index < TUT_NumberPointers; index++) { tutPointer[index].pointerType = TUT_PointerTypeNone; tutPointerShip = NULL; tutPointerShipGroupRect = tutPointerShipHealthRect = NULL; } tutFEContextMenuShipType = 0; } void tutTutorial1(char *name, featom *atom) { static bool beginning; if (FEFIRSTCALL(atom)) { beginning = FALSE; } else if (FELASTCALL(atom)) { if (!beginning) { tutorial = 0; } } else { beginning = TRUE; tutorial = 1; dbgAssert(startingGame == FALSE); dbgMessagef("\nTutorial1 started"); utySinglePlayerGameStart(name, atom); } } /*----------------------------------------------------------------------------- Name : tutPointerAllocate Description : Allocate a tutorial pointer from the pointer list. Inputs : name - name of pointer. Will overwrite pointers of same name. type - type of pointer to allocate. Outputs : Return : pointer to pointer. Quaint isn't it? ----------------------------------------------------------------------------*/ tutpointer *tutPointerAllocate(char *name, sdword type) { sdword index, freeIndex = -1; for (index = 0; index < TUT_NumberPointers; index++) { //make sure this name is unique if (!strcmp(name, tutPointer[index].name)) { //if this one is the same name if (tutPointer[index].ship == tutPointerShip) { tutPointerShip = NULL; tutPointerShipGroupRect = tutPointerShipHealthRect = NULL; } freeIndex = index; break; } if (tutPointer[index].pointerType == TUT_PointerTypeNone) { //if this one is free freeIndex = index; } } #ifndef HW_Release if (freeIndex < 0) { dbgFatalf(DBG_Loc, "Cannot allocate tutorial pointer '%s'.", name); } #endif memStrncpy(tutPointer[freeIndex].name, name, TUT_PointerNameMax); tutPointer[freeIndex].pointerType = type; return(&tutPointer[freeIndex]); } void tutSetPointerTargetXY(char *name, sdword x, sdword y) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeXY); pointer->x = x; pointer->y = y; } //sets the tutorial pointer relative to the right side of the screen void tutSetPointerTargetXYRight(char *name, sdword x, sdword y) { tutSetPointerTargetXY(name, MAIN_WindowWidth+x-640, y); } //sets the tutorial pointer relative to the bottom right corner of the screen void tutSetPointerTargetXYBottomRight(char *name, sdword x, sdword y) { tutSetPointerTargetXY(name, MAIN_WindowWidth+x-640, MAIN_WindowHeight+y-480); } void tutSetPointerTargetXYTaskbar(char *name, sdword x, sdword y) { tutSetPointerTargetXY(name, feResRepositionX(x), MAIN_WindowHeight+y-480); } void tutSetPointerTargetXYFE(char *name, sdword x, sdword y) { tutSetPointerTargetXY(name, feResRepositionX(x), feResRepositionY(y)); } void tutSetPointerTargetShip(char *name, ShipPtr ship) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeShip); pointer->ship = ship; } void tutSetPointerTargetShipSelection(char *name, SelectCommand *ships) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeShips); pointer->selection = ships; } void tutSetPointerTargetShipHealth(char *name, ShipPtr ship) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeShipHealth); pointer->ship = ship; tutPointerShip = ship; tutPointerShipHealthRect = &pointer->rect; } void tutSetPointerTargetShipGroup(char *name, ShipPtr ship) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeShipGroup); pointer->ship = ship; tutPointerShip = ship; tutPointerShipGroupRect = &pointer->rect; } void tutPlayerShipDied(ShipPtr ship) { sdword index; for (index = 0; index < TUT_NumberPointers; index++) { if (tutPointer[index].ship == ship) { tutPointer[index].pointerType = TUT_PointerTypeNone; tutPointer[index].ship = NULL; } } if(ship == tutPointerShip) { //tutTextPointerType = TUT_PointerTypeNone; tutPointerShip = NULL; tutPointerShipGroupRect = tutPointerShipHealthRect = NULL; } } void tutSetPointerTargetFERegion(char *name, char *pAtomName) { regionhandle reg; reg = regFindChildByAtomName(®RootRegion, pAtomName); if(reg) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeRegion); pointer->rect = reg->rect; pointer->rect.x0 -= 1; pointer->rect.y0 -= 1; pointer->rect.y1 += 2; } } void tutSetPointerTargetRect(char *name, sdword x0, sdword y0, sdword x1, sdword y1) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeRegion); pointer->rect.x0 = x0; pointer->rect.y0 = y0; pointer->rect.x1 = x1; pointer->rect.y1 = y1; } void tutSetPointerTargetAIVolume(char *name, Volume *volume) { if (volume != NULL) { tutpointer *pointer = tutPointerAllocate(name, TUT_PointerTypeAIVolume); pointer->volume = volume; } } /*----------------------------------------------------------------------------- Name : tutRemovePointerByName Description : Turn off a named pointer. Inputs : name - name of pointer to remove Outputs : Return : ----------------------------------------------------------------------------*/ void tutRemovePointerByName(char *name) { sdword index; for (index = 0; index < TUT_NumberPointers; index++) { if (!strcmp(tutPointer[index].name, name)) { tutPointer[index].pointerType = TUT_PointerTypeNone; if (tutPointer[index].ship == tutPointerShip) { tutPointerShip = NULL; tutPointerShipGroupRect = tutPointerShipHealthRect = NULL; } return; } } #ifndef HW_Debug dbgMessagef("\ntutRemovePointerByName: '%s' not found.", name); #endif } /*----------------------------------------------------------------------------- Name : tutRemoveAllPointers Description : Remove all pointers. Gone. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutRemoveAllPointers(void) { sdword index; for (index = 0; index < TUT_NumberPointers; index++) { if (tutPointer[index].pointerType != TUT_PointerTypeNone) { tutPointer[index].pointerType = TUT_PointerTypeNone; if (tutPointer[index].ship == tutPointerShip) { tutPointerShip = NULL; tutPointerShipGroupRect = tutPointerShipHealthRect = NULL; } } } } // This function sets the current text display position and size void tutSetTextDisplayBox(sdword x, sdword y, sdword width, sdword height, bool bScale) { if(bScale) { x = (long)( ((real32)x / 640.0f) * (real32)MAIN_WindowWidth ); y = (long)( ((real32)y / 480.0f) * (real32)MAIN_WindowHeight ); } else { x += ((MAIN_WindowWidth - 640) / 2); y += ((MAIN_WindowHeight - 480) / 2); } tutTextPosX = x+5; tutTextPosY = y+5; tutTextSizeX = width-10; tutTextSizeY = height-10; tutTextRect.x0 = x; tutTextRect.y0 = y; tutTextRect.x1 = x + width; tutTextRect.y1 = y + height; } /*----------------------------------------------------------------------------- Name : tutSetTextDisplayBoxToSubtitleRegion Description : Causes pointers to be clipped to the subtitle region Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutSetTextDisplayBoxToSubtitleRegion(void) { tutTextRect = subRegion[STR_LetterboxBar].rect; } void tutRootDrawFunction(regionhandle reg) { sdword index; regionhandle escapeRegion = NULL; if (reg->previous) { for (index = 0; index <= feStackIndex; index++) { if (feStack[index].screen != NULL) { if (strcmp(feStack[index].screen->name, "Construction_manager") && strcmp(feStack[index].screen->name, "Launch_Manager") && strcmp(feStack[index].screen->name, "Research_Manager") && strcmp(feStack[index].screen->name, "Sensors_manager")) { //if it's not one of the screens the turorial teaches escapeRegion = feStack[index].baseRegion; break; } } } //we want the tutorial stuff to be on top of all menu screens EXCEPT the in-game escape menu and it's minions if (escapeRegion == NULL) { //don't put it on top of the build manager or any other base-level manager. regSiblingMoveToFront(reg); } } } void tutAllocateRootRegion(void) { if(tutRootRegionCount == 0) { tutRootRegion = regChildAlloc(ghMainRegion, (sdword)&tutRootAtom, tutRootAtom.x, tutRootAtom.y, tutRootAtom.width, tutRootAtom.height, 0, RPE_DrawEveryFrame); tutRootAtom.region = (void*)tutRootRegion; tutRootRegion->atom = &tutRootAtom; tutRootAtom.pData = NULL; regDrawFunctionSet(tutRootRegion, tutRootDrawFunction); } tutRootRegionCount++; } void tutDeallocateRootRegion(void) { tutRootRegionCount--; if(tutRootRegionCount == 0) { if(tutRootRegion) regRegionDelete(tutRootRegion); tutRootRegion = NULL; } } // This function will accept a string to be displayed in the current text box. // The current text box is set up with the tutSetTextDisplayBox() function. void tutShowText(char *szText) { fonthandle currFont; sdword Height; char Line[256], *pString; if(tutTextVisible) tutHideText(); if (MAIN_WindowWidth >= 1024) { tutTextFont = frFontRegister("ScrollingText.hff"); } else { tutTextFont = frFontRegister("SimplixSSK_13.hff"); } Height = 0; pString = szText; currFont = fontMakeCurrent(tutTextFont); do { pString = tutGetNextTextLine(Line, pString, tutTextSizeX); Height += fontHeight(" "); } while(pString && pString[0]); fontMakeCurrent(currFont); tutAllocateRootRegion(); tutTextAtom.x = tutTextPosX-5; tutTextAtom.y = tutTextPosY-5; tutTextAtom.width = tutTextSizeX + 10; tutTextAtom.height = max(Height, tutTextSizeY)+10; tutTextRect.x0 = tutTextPosX-5; tutTextRect.y0 = tutTextPosY-5; tutTextRect.x1 = tutTextRect.x0 + tutTextSizeX + 10; tutTextRect.y1 = tutTextRect.y0 + max(Height, tutTextSizeY) + 10; tutTextRegion = regChildAlloc(tutRootRegion, (sdword)&tutTextAtom, tutTextAtom.x, tutTextAtom.y, tutTextAtom.width, tutTextAtom.height, 0, 0); tutTextAtom.region = (void*)tutTextRegion; tutTextRegion->atom = &tutTextAtom; tutTextAtom.pData = (ubyte *)szText; tutTextVisible = TRUE; regDrawFunctionSet(tutTextRegion, tutDrawTextFunction); } void tutHideText(void) { // sdword index; if(tutTextRegion) { regRegionDelete(tutTextRegion); tutDeallocateRootRegion(); } tutTextRegion = NULL; tutTextVisible = FALSE; tutRemoveAllPointers(); //kills the speech associated with the text speechEventActorStop(ACTOR_FLEETCOMMAND_FLAG, 0.1f); } /*----------------------------------------------------------------------------- Name : tutIsspace Description : Returns TRUE if the character is a "space" character Inputs : c - the character to test Outputs : Return : ----------------------------------------------------------------------------*/ bool tutIsspace(char c) { if (c==' '||c=='\n') { return TRUE; } return FALSE; } // This function gets a line of text that is up to Width pixels wide, and returns a // pointer to the start of the next line. Assumes the current font is set. char *tutGetNextTextLine(char *pDest, char *pString, long Width) { long WordLen, StringLen; char *pstr; long Done = FALSE; char temp; StringLen = 0; WordLen = 0; *pDest = 0; if(pString[0] == 0) return NULL; do { // Skip leading whitespace pstr = &pString[StringLen]; while( *pstr && *pstr != '\n' && (*pstr == '-' || tutIsspace(*pstr)) ) { WordLen++; pstr++; } if(*pstr && *pstr != '\n') { while( *pstr && *pstr != '\n' && *pstr != '-' && !tutIsspace(*pstr) ) { WordLen++; pstr++; } temp = *pstr; *pstr = 0; if(fontWidth(pString) > Width) Done = TRUE; else { StringLen += WordLen; WordLen = 0; } *pstr = temp; } else { Done = TRUE; StringLen += WordLen; } } while(!Done); if(StringLen) { memStrncpy(pDest, pString, StringLen+1); //pDest[StringLen] = 0; while( pString[StringLen] && tutIsspace(pString[StringLen]) ) StringLen++; } else return NULL; return pString + StringLen; } static long PulseVal(long Val) { static long pulseDir = TUT_PointerPulseInc; Val += pulseDir; if(Val >= 255 || Val <= TUT_PointerPulseMin) { pulseDir = -pulseDir; Val += pulseDir; } return Val; } // long vector type for the clipper typedef struct { sdword x,y; } lvector; // Clips segment to a horizontal line at y. // Puts the intersection point in the return vector at *pDest // returns true if clipped, false otherwise sdword tutClipSegToHorizontal(lvector *pSeg, lvector *pDest, sdword y) { sdword dy0, dy1; real32 t; dy0 = pSeg[1].y - pSeg[0].y; dy1 = y - pSeg[0].y; t = (real32)dy1 / dy0; if(t > 0.0f && t < 1.0f) { pDest->y = y; pDest->x = pSeg[0].x + (sdword)((real32)(pSeg[1].x - pSeg[0].x) * t + 0.5f); return 1; } else return 0; } // Clips segment to a vertical line at x. // Puts the intersection point in the return vector at *pDest // returns true if clipped, false otherwise sdword tutClipSegToVertical(lvector *pSeg, lvector *pDest, sdword x) { sdword dx0, dx1; real32 t; dx0 = pSeg[1].x - pSeg[0].x; dx1 = x - pSeg[0].x; t = (real32)dx1 / dx0; if(t > 0.0f && t < 1.0f) { pDest->x = x; pDest->y = pSeg[0].y + (sdword)((real32)(pSeg[1].y - pSeg[0].y) * t + 0.5f); return 1; } else return 0; } void tutClipSegToTextBox(sdword *x0, sdword *y0, sdword *x1, sdword *y1) { lvector ClipSeg[2]; lvector Clipped; ClipSeg[0].x = *x0; ClipSeg[0].y = *y0; ClipSeg[1].x = *x1; ClipSeg[1].y = *y1; if(tutClipSegToHorizontal(ClipSeg, &Clipped, tutTextRect.y0)) { if(Clipped.x >= tutTextRect.x0 && Clipped.x <= tutTextRect.x1) ClipSeg[0] = Clipped; } if(tutClipSegToHorizontal(ClipSeg, &Clipped, tutTextRect.y1)) { if(Clipped.x >= tutTextRect.x0 && Clipped.x <= tutTextRect.x1) ClipSeg[0] = Clipped; } if(tutClipSegToVertical(ClipSeg, &Clipped, tutTextRect.x0)) { if(Clipped.y >= tutTextRect.y0 && Clipped.y <= tutTextRect.y1) ClipSeg[0] = Clipped; } if(tutClipSegToVertical(ClipSeg, &Clipped, tutTextRect.x1)) { if(Clipped.y >= tutTextRect.y0 && Clipped.y <= tutTextRect.y1) ClipSeg[0] = Clipped; } *x0 = ClipSeg[0].x; *y0 = ClipSeg[0].y; *x1 = ClipSeg[1].x; *y1 = ClipSeg[1].y; } /*----------------------------------------------------------------------------- Name : tutDrawTextPointers Description : Draw all active tutorial pointers Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutDrawTextPointers(rectangle *pRect) { sdword x0, y0, x1, y1, index; real32 x, y, rad, angle, dx, dy, magnitude; static long tutPulse = TUT_PointerPulseMin; //hmatrix modelview, projection; real32 sx, sy; tutpointer *pointer; color c; vector temp; for (pointer = tutPointer, index = 0; index < TUT_NumberPointers; index++, pointer++) { //for each pointer switch(pointer->pointerType) { case TUT_PointerTypeNone: break; //not active; ignore case TUT_PointerTypeXY: x0 = (pRect->x0 + pRect->x1) / 2; y0 = (pRect->y0 + pRect->y1) / 2; x1 = pointer->x;//tutPointerX; y1 = pointer->y;//tutPointerY; tutClipSegToTextBox(&x0, &y0, &x1, &y1); c = colRGB(tutPulse, tutPulse, tutPulse); primLine2(x0, y0, x1, y1, c); dx = (real32)(x0 - x1); //vector from arrowhead to source dy = (real32)(y0 - y1); if (dx != 0.0f || dy != 0.0f) { //if not zero-length vector magnitude = fmathSqrt(dx * dx + dy * dy); //magnitude of vector dx /= magnitude; dy /= magnitude; //normalize the vector if (dx == 0.0f) { //singularity: vertical axis if (dy > 0.0f) { angle = PI / 2.0f; //90 } else { angle = PI * 3.0f / 2.0f; //270 } } else if (dy > 0.0f) { //0..180 if (dx > 0.0f) { //0..90 angle = (real32)atan((double)(dy / dx)); } else { //90..180 angle = PI - (real32)atan((double)(dy / -dx)); } } else { //180..360 if (dx < 0.0f) { //180..270 angle = (real32)atan((double)(dy / dx)) + PI; } else { //270..360 angle = 2.0 * PI - (real32)atan((double)(-dy / dx)); } } //now we have angle of main vector; offset that to get arrowhead vectors x0 = x1 + (sdword)(cos((double)(angle - TUT_ArrowheadAngle)) * TUT_ArrowheadLength); y0 = y1 + (sdword)(sin((double)(angle - TUT_ArrowheadAngle)) * TUT_ArrowheadLength); primLine2(x0, y0, x1, y1, c); x0 = x1 + (sdword)(cos((double)(angle + TUT_ArrowheadAngle)) * TUT_ArrowheadLength); y0 = y1 + (sdword)(sin((double)(angle + TUT_ArrowheadAngle)) * TUT_ArrowheadLength); primLine2(x0, y0, x1, y1, c); } break; case TUT_PointerTypeShip: rad = pointer->ship->collInfo.selCircleRadius; x = pointer->ship->collInfo.selCircleX; y = pointer->ship->collInfo.selCircleY; goto shipsCase; //rest of code is common case TUT_PointerTypeShips: selSelectionDimensions(&rndCameraMatrix, &rndProjectionMatrix, pointer->selection, &x, &y, &rad); shipsCase: if(rad > 0.0) { //if ship is on-screen real32 sx, sy, deltx, delty, len; rad = max(rad, TUT_ShipCircleSizeMin); //x = pointer->ship->collInfo.selCircleX; //y = pointer->ship->collInfo.selCircleY; primGLCircleOutline2(x, y, rad, pieCircleSegmentsCompute(rad), colRGB(tutPulse/2, tutPulse, tutPulse/2)); sx = primScreenToGLX((pRect->x0 + pRect->x1) / 2); sy = primScreenToGLY((pRect->y0 + pRect->y1) / 2); deltx = x-sx; delty = y-sy; len = (real32)fsqrt(deltx*deltx + delty*delty); len = (len - rad) / len; if (len > 0.0f) { x0 = primGLToScreenX(sx); y0 = primGLToScreenY(sy); x1 = primGLToScreenX(sx + deltx * len); y1 = primGLToScreenY(sy + delty * len); tutClipSegToTextBox(&x0, &y0, &x1, &y1); primLine2(x0, y0, x1, y1, colRGB(tutPulse/2, tutPulse, tutPulse/2)); } } break; case TUT_PointerTypeShipHealth: rad = pointer->ship->collInfo.selCircleRadius; if(rad > 0.0) { //if ship on-screen x0 = (pRect->x0 + pRect->x1) / 2; y0 = (pRect->y0 + pRect->y1) / 2; x1 = (pointer->rect.x0 + pointer->rect.x1) / 2; y1 = pointer->rect.y0; tutClipSegToTextBox(&x0, &x1, &y0, &y1); primLine2(x0, y0, x1, y1, colRGB(tutPulse/2, tutPulse, tutPulse/2)); primRectOutline2(&pointer->rect, 1, colRGB(tutPulse/2, tutPulse, tutPulse/2)); } break; case TUT_PointerTypeShipGroup: rad = pointer->ship->collInfo.selCircleRadius; if(rad > 0.0) { //if ship on-screen x0 = (pRect->x0 + pRect->x1) / 2; y0 = (pRect->y0 + pRect->y1) / 2; x1 = (pointer->rect.x0 + pointer->rect.x1) / 2; y1 = pointer->rect.y0; tutClipSegToTextBox(&x0, &y0, &x1, &y1); primLine2(x0, y0, x1, y1, colRGB(tutPulse/2, tutPulse, tutPulse/2)); primRectOutline2(&pointer->rect, 1, colRGB(tutPulse/2, tutPulse, tutPulse/2)); } break; case TUT_PointerTypeRegion: primRectOutline2(&pointer->rect, 3, colRGB(tutPulse, tutPulse, tutPulse)); break; case TUT_PointerTypeAIVolume: temp = volFindCenter(pointer->volume); selCircleComputeGeneral(&rndCameraMatrix, &rndProjectionMatrix, (vector *)&temp, volFindRadius(pointer->volume), &sx, &sy, &rad); if(rad > 0.0) { real32 x, y, deltx, delty, len; rad = max(rad, TUT_ShipCircleSizeMin); x = sx; y = sy; primGLCircleOutline2(x, y, rad, pieCircleSegmentsCompute(rad), colRGB(tutPulse/2, tutPulse, tutPulse/2)); sx = primScreenToGLX((pRect->x0 + pRect->x1) / 2); sy = primScreenToGLY((pRect->y0 + pRect->y1) / 2); deltx = x-sx; delty = y-sy; len = (real32)fsqrt(deltx*deltx + delty*delty); len = (len - rad) / len; x0 = primGLToScreenX(sx); y0 = primGLToScreenY(sy); x1 = primGLToScreenX(sx + deltx * len); y1 = primGLToScreenY(sy + delty * len); tutClipSegToTextBox(&x0, &y0, &x1, &y1); primLine2(x0, y0, x1, y1, colRGB(tutPulse/2, tutPulse, tutPulse/2)); } break; } } tutPulse = PulseVal(tutPulse); tutPointersDrawnThisFrame = TRUE; } // This function actually handles drawing the text in the region added by tutShowText void tutDrawTextFunction(regionhandle reg) { char *pString; char Line[256]; long x, y, Width; fonthandle currFont; featom *pAtom = (featom *)reg->atom; rectangle rect; rect = reg->rect; // if(tutTextPointerType != TUT_PointerTypeNone) if (!tutPointersDrawnThisFrame) { tutDrawTextPointers(&rect); } // Draw the translucent blue box behind the text primRectTranslucent2(&rect, colRGBA(0, 0, 64, 192)); currFont = fontMakeCurrent(tutTextFont); x = rect.x0+5; y = rect.y0+5; Width = (rect.x1 - rect.x0) - 10; pString = (char *)pAtom->pData; do { pString = tutGetNextTextLine(Line, pString, Width); if(Line[0]) fontPrintf(x, y, colRGB(255, 255, 128), "%s", Line); y += fontHeight(" "); } while(pString && pString[0]); fontMakeCurrent(currFont); } void tutShowNextButton(void) { if(tutNextVisible) tutHideNextButton(); tutAllocateRootRegion(); tutNextAtom.x = tutTextRect.x0 + 128; tutNextAtom.y = tutTextRect.y1; tutNextAtom.width = 64; tutNextAtom.height = 32; tutNextRegion = (buttonhandle)regChildAlloc(tutRootRegion, (sdword)&tutNextAtom, tutNextAtom.x, tutNextAtom.y, tutNextAtom.width, tutNextAtom.height, sizeof(buttonhandle) - sizeof(regionhandle), 0); tutNextAtom.region = (void*)tutNextRegion; tutNextRegion->reg.atom = &tutNextAtom; tutNextRegion->reg.flags |= RPM_MouseEvents; tutNextAtom.pData = NULL; tutNextRegion->reg.processFunction = uicButtonProcess; tutNextRegion->processFunction = tutProcessNextButton; tutNextVisible = TRUE; regDrawFunctionSet((regionhandle)tutNextRegion, tutDrawNextButtonFunction); } void tutHideNextButton(void) { if(tutNextRegion) { regRegionDelete((regionhandle)tutNextRegion); tutDeallocateRootRegion(); } tutNextRegion = NULL; tutNextVisible = FALSE; } udword tutProcessNextButton(struct tagRegion *reg, sdword ID, udword event, udword data) { if(event == CM_ButtonClick) { tutNextButtonState = 1; return 1; } return 0; } void tutDrawNextButtonFunction(regionhandle reg) { if(mouseInRect(®->rect)) { if(mouseLeftButton()) trRGBTextureMakeCurrent(tutTexture[TUT_NEXT_ON]); else trRGBTextureMakeCurrent(tutTexture[TUT_NEXT_MOUSE]); } else trRGBTextureMakeCurrent(tutTexture[TUT_NEXT_OFF]); rndPerspectiveCorrection(FALSE); // glEnable(GL_BLEND); primRectSolidTextured2(®->rect); // glDisable(GL_BLEND); } sdword tutNextButtonClicked(void) { sdword RetVal; RetVal = tutNextButtonState; tutNextButtonState = 0; return RetVal; } void tutShowBackButton(void) { if(tutBackVisible) { tutPrevVisible = FALSE; tutHideBackButton(); } tutAllocateRootRegion(); tutBackAtom.x = tutTextRect.x0; tutBackAtom.y = tutTextRect.y1; tutBackAtom.width = 128; tutBackAtom.height = 32; tutBackRegion = (buttonhandle)regChildAlloc(tutRootRegion, (sdword)&tutBackAtom, tutBackAtom.x, tutBackAtom.y, tutBackAtom.width, tutBackAtom.height, sizeof(buttonhandle) - sizeof(regionhandle), 0); tutBackAtom.region = (void*)tutBackRegion; tutBackRegion->reg.atom = &tutBackAtom; tutBackRegion->reg.flags |= RPM_MouseEvents; tutBackAtom.pData = NULL; tutBackRegion->reg.processFunction = uicButtonProcess; tutBackRegion->processFunction = tutProcessBackButton; tutBackVisible = TRUE; regDrawFunctionSet((regionhandle)tutBackRegion, tutDrawBackButtonFunction); } void tutShowPrevButton(void) { if (tutBackVisible) { tutHideBackButton(); } tutPrevVisible = TRUE; tutShowBackButton(); } void tutHideBackButton(void) { if(tutBackRegion) { regRegionDelete((regionhandle)tutBackRegion); tutDeallocateRootRegion(); } tutBackRegion = NULL; tutBackVisible = FALSE; tutPrevVisible = FALSE; } udword tutProcessBackButton(struct tagRegion *reg, sdword ID, udword event, udword data) { if(event == CM_ButtonClick) { if((tutPrevVisible) && (tutLastLessonName[0])) strcpy(tutCurrLessonName, tutLastLessonName); if (fileExists(tutCurrLessonName, 0) && (VerifySaveFile(tutCurrLessonName) == VERIFYSAVEFILE_OK)) { tutEnableEverything(); spMainScreen(); tbForceTaskbar(FALSE); gameEnd(); tutorial = 1; utyLoadSinglePlayerGameGivenFilename(tutCurrLessonName); return 1; } } return 0; } void tutDrawBackButtonFunction(regionhandle reg) { if (tutPrevVisible) { //put in pointer to prevlesson texture here if(mouseInRect(®->rect)) { if(mouseLeftButton()) trRGBTextureMakeCurrent(tutTexture[TUT_PREV_ON]); else trRGBTextureMakeCurrent(tutTexture[TUT_PREV_MOUSE]); } else trRGBTextureMakeCurrent(tutTexture[TUT_PREV_OFF]); } else { //the back button is displayed as a "Restart Lesson" if(mouseInRect(®->rect)) { if(mouseLeftButton()) trRGBTextureMakeCurrent(tutTexture[TUT_REST_ON]); else trRGBTextureMakeCurrent(tutTexture[TUT_REST_MOUSE]); } else trRGBTextureMakeCurrent(tutTexture[TUT_REST_OFF]); } rndPerspectiveCorrection(FALSE); // glEnable(GL_BLEND); primRectSolidTextured2(®->rect); // glDisable(GL_BLEND); } // Returns the next "StartFrom" value, and copies the token into pDest long GetNextCommaDelimitedToken(char *pString, char *pDest, long StartFrom) { static char *pSrc = NULL; long Index = 0, Len; if(pString) { pSrc = pString; Index = 0; } if(pSrc) { Index = StartFrom; Len = 0; while(pSrc[Index] && pSrc[Index] != ',' && pSrc[Index] != 0x0a && pSrc[Index] != 0x0d) { pDest[Len] = pSrc[Index]; Len++; Index++; } pDest[Len] = 0; if(pSrc[Index] == ',') Index++; else pSrc = NULL; } else return 0; return Index; } long tutFindTokenIndex(char *pTokenList[], char *pToken) { long i; i = 0; while(pTokenList[i][0]) { if(stricmp(pTokenList[i], pToken) == 0) return i; i++; } return -1; } long tutParseImagesIntoIndices(char *szImages) { char szToken[256]; long StrIndex, Count, TokenIndex; Count = 0; StrIndex = GetNextCommaDelimitedToken(szImages, szToken, 0); while(StrIndex) { TokenIndex = tutFindTokenIndex(tutImageList, szToken); if(TokenIndex != -1) szImageIndexList[Count] = TokenIndex; else szImageIndexList[Count] = 0; Count++; StrIndex = GetNextCommaDelimitedToken(NULL, szToken, StrIndex); } szImageIndexList[Count] = 0; return Count; } /* This function will accept a comma delimited list of images to be displayed, in order of appearance in this list, from left to right on the screen. The image list is included in the header. */ void tutShowImages(char *szImages) { long ImageCount; if(tutImageVisible) tutHideImages(); tutAllocateRootRegion(); ImageCount = tutParseImagesIntoIndices(szImages); tutImageAtom.x = MAIN_WindowWidth - ImageCount * 64; tutImageAtom.y = MAIN_WindowHeight - 64; tutImageAtom.width = ImageCount * 64; tutImageAtom.height = 64; tutImageRegion = regChildAlloc(tutRootRegion, (sdword)&tutImageAtom, tutImageAtom.x, tutImageAtom.y, tutImageAtom.width, tutImageAtom.height, 0, 0); tutImageAtom.region = (void*)tutImageRegion; tutImageRegion->atom = &tutImageAtom; tutImageAtom.pData = szImages; tutImageVisible = TRUE; regDrawFunctionSet(tutImageRegion, tutDrawImageFunction); } void tutDrawImageFunction(regionhandle reg) { rectangle rect; long i, Index; long x, y; x = reg->rect.x0; y = reg->rect.y0; // glEnable(GL_BLEND); i = 0; while(szImageIndexList[i]) { Index = szImageIndexList[i]; trRGBTextureMakeCurrent(tutTexture[Index]); rndPerspectiveCorrection(FALSE); rect.x0 = x + (64 * i); rect.y0 = y; rect.x1 = x + (64 * i) + 64; rect.y1 = y + 64; primRectSolidTextured2(&rect); i++; } // glDisable(GL_BLEND); } void tutHideImages(void) { if(tutImageRegion) { regRegionDelete(tutImageRegion); tutDeallocateRootRegion(); } tutImageRegion = NULL; tutImageVisible = FALSE; } /*----------------------------------------------------------------------------- Name : tutStartup Description : tutorial init function called at game startup Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutStartup(void) { sdword index; for (index = 0; tutImageList[index][0]; index++) { tutTexture[index] = TR_InvalidInternalHandle; tutImage[index] = NULL; } } /*----------------------------------------------------------------------------- Name : tutShutdown Description : Shutdown function called at game shutdown time Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutShutdown(void) { ; } /*----------------------------------------------------------------------------- Name : tutInitialize Description : Tutorial init function called once for every tutorial load Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutInitialize(void) { long i; char Filename[256]; i = 0; while( tutImageList[i][0] ) { if (tutTexture[i] == TR_InvalidInternalHandle) { dbgAssert(tutImage[i] == NULL); strcpy(Filename, "feman\\texdecorative\\"); //load the correct texture depending on language if (strCurLanguage == languageEnglish) { strcat(Filename, tutImageList[i]); } else if (strCurLanguage == languageFrench) { strcat(Filename, tutFrenchImageList[i]); } else if (strCurLanguage == languageGerman) { strcat(Filename, tutGermanImageList[i]); } else if (strCurLanguage == languageSpanish) { strcat(Filename, tutSpanishImageList[i]); } else if (strCurLanguage == languageItalian) { strcat(Filename, tutItalianImageList[i]); } else { //defaults to english strcat(Filename, tutImageList[i]); } strcat(Filename, ".LiF"); tutImage[i] = trLIFFileLoad(Filename, NonVolatile); dbgAssert(tutImage[i] != NULL); tutTexture[i] = trRGBTextureCreate((color *)tutImage[i]->data, tutImage[i]->width, tutImage[i]->height, TRUE); i++; } } } /*----------------------------------------------------------------------------- Name : tutUnInitialize Description : Tutorial shutdown function called at the end of a tutorial game Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void tutUnInitialize(void) { long i; tutHideText(); tutHideImages(); tutHideNextButton(); tutHideBackButton(); i = 0; while( tutImageList[i][0] ) { if(tutImage[i] != NULL) { memFree(tutImage[i]); tutImage[i] = NULL; } if (tutTexture[i] != TR_InvalidInternalHandle) { trRGBTextureDelete(tutTexture[i]); tutTexture[i] = TR_InvalidInternalHandle; } i++; } tutEnableEverything(); } void tutSetFlagIndex(long Index, long Val) { long *pFlagMem; long FlagBit; //hack code to get speech to work when game paused if (Index == 1) { FalkosFuckedUpTutorialFlag = !Val; } pFlagMem = (long *)&tutEnable; pFlagMem += Index/32; FlagBit = 1 << (Index & 31); if(Val) *pFlagMem |= FlagBit; else *pFlagMem &= ~FlagBit; } void tutEnableEverything(void) { long i; for(i=0; ishiptype == st) j++; } return j; } sdword tutSelectedContainsShipTypes(char *pShipTypes) { ShipType st; char szToken[256]; long StrIndex, Count; Count = 0; StrIndex = GetNextCommaDelimitedToken(pShipTypes, szToken, 0); while(StrIndex) { st = StrToShipType(szToken); Count += tutSelectedContainsShipType(st); StrIndex = GetNextCommaDelimitedToken(NULL, szToken, StrIndex); } return Count; } void tutGameMessage(char *commandName) { if(!tutorial) return; dbgMessagef("\ntutGameMessage: '%s'", commandName); if( tutGameMessageIndex < 16 ) { strcpy(tutGameMessageList[ tutGameMessageIndex ], commandName); tutGameMessageIndex++; } } sdword tutGameSentMessage(char *commandNames) { sdword RetVal = 0, i; char szToken[256]; long StrIndex, Count; Count = 0; StrIndex = GetNextCommaDelimitedToken(commandNames, szToken, 0); while(StrIndex) { for(i=0; iship; if (factoryship->playerowner == universe.curPlayerPtr) { for (index = 0, progress = &sinprogress->progress[0]; index < TOTAL_STD_SHIPS; index++, progress++) { if(progress->info && progress->info->shiptype == st) return progress->nJobs; } } node = node->next; } return 0; } //external function definition shipinprogress *cmSIP(udword index); /*----------------------------------------------------------------------------- Name : tutBuildManagerShipTypeSelected Description : Returns TRUE if the shiptype is selected in the build manager Inputs : pShipType - string of shiptypes Outputs : Return : TRUE or FALSE ----------------------------------------------------------------------------*/ sdword tutBuildManagerShipTypeSelected(char *pShipType) { ShipType shiptype; shipinprogress *shipprog; shiptype = StrToShipType(pShipType); shipprog = cmSIP(shiptype); if (shipprog->selected) { return 1; } else { return 0; } } long tutCameraFocusShipCount(ShipType st) { long Count = 0; CameraStackEntry *entry; long i; entry = currentCameraStackEntry(&universe.mainCameraCommand); for(i=0; ifocus.numShips; i++) { if(entry->focus.ShipPtr[i]->shiptype == st) Count++; } return Count; } sdword tutCameraFocusedOnShipType(char *pShipTypes) { char szToken[256]; long StrIndex, Count; ShipType st; if (smSensorsActive) { //camera can't be focused on a ship in the Sensors Manager return 0; } Count = 0; StrIndex = GetNextCommaDelimitedToken(pShipTypes, szToken, 0); while(StrIndex) { st = StrToShipType(szToken); Count += tutCameraFocusShipCount(st); StrIndex = GetNextCommaDelimitedToken(NULL, szToken, StrIndex); } return Count; }