12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2016 RWS Inc, All Rights Reserved
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of version 2 of the GNU General Public License as published by
- // the Free Software Foundation
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License along
- // with this program; if not, write to the Free Software Foundation, Inc.,
- // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // credits.cpp
- // Project: Postal
- //
- // This module deals with displaying the credits.
- //
- // History:
- // 12/05/96 MJR Started.
- //
- // 12/19/96 JMI Scope error in Credits(). Loop was waiting for terminators
- // one of which was lKey. The lKey was being set via a call
- // to rspGetKey(&lKey). But there were two lKeys. One inside
- // and one outside the loop. The one on the outside was
- // evaluated and the one on the inside was being set to the
- // current key.
- //
- // 02/17/97 JMI Making this obey rspGetQuitStatus().
- //
- // 07/05/97 MJR Changed to RSP_BLACK_INDEX instead of 0.
- //
- // 07/16/97 BRH Changed the credits screen to the "What's in the
- // release version of postal preview" screen for the
- // demo. Took out blah blah blah, yada yada yada.
- //
- // 08/11/97 JRD Transforming this module into a device for scolling text
- // which is intended to be used both by credits and by story.
- // It wil operate similar to cutscene in that all of it's
- // assets and memory usage is assumed temporary. It will still
- // use the shell sak for assets.
- //
- // 08/11/97 JRD Created a class for the purpose of accessing generic files
- // from within a sak directory. Used to read in credits metafile.
- //
- // 08/20/97 BRH Added music to credits. Unfortunately, I hardwired the music in
- // the function ScrollPage instead of Credits(), so the mustic will
- // play in any part of the game where text is scrolled. Man, was I
- // "stupid" when I did that.
- //
- // 08/21/97 JMI Changed call to Update() to UpdateSystem() and occurrences
- // of rspUpdateDisplay() to UpdateDisplay().
- //
- // 08/22/97 JRD Attempted to make the credits locking safe.
- //
- // 08/22/97 JMI Changed calls to UpdateDisplay() back to rspUpdateDisplay()
- // since we no longer need UpdateDisplay() now that we are
- // using rspLock/Unlock* functions properly.
- //
- // 08/26/97 JRD Moved the credit music into the credits function from the
- // text scrolling function.
- //
- // 08/27/97 JRD Moved end sound out of Scroll Page. Made Scroll page not clear screen
- // at end. Added special credit ending.
- //
- // 08/27/97 JRD Removed text dependency on windows colors. Made it so if credits
- // are aborted, ending is not shown.
- //
- // 08/28/97 JRD Altered Credits() to allow varying the resources so
- // different music could play in the final scene than
- // in the normal credits.
- //
- // 09/08/97 JRD Had Bill add rspGetQuitStaus() to the list of keys and
- // mouse buttons that abort the credits. Boy, did I look
- // "stupid" when someone hit Alt-F4 during the ending
- // sequence only to get stuck on the credits. Thanks for
- // fixing that Bill, I owe you another trip to Las Vegas.
- //
- // 09/17/97 BRH Added in a conditional compile optionfor the credits so
- // the shareware version will show the coming soon screen
- // instead of the credits.
- //
- // 06/24/01 MJR Changed from obsolete macro to SHOW_EXIT_SCREEN as a way
- // to control what gets displayed when the player exits from
- // the game. Also renamed macro to EXIT_BG and changed the
- // filename to "exit.bmp".
- //
- ////////////////////////////////////////////////////////////////////////////////
- // SCROLL PAGE HACK: CURRENTLY USES COLOR 244 = {128,0,0}, 245 = {255,0,0}
- #include "RSPiX.h"
- #include "credits.h"
- #include "game.h"
- #include "update.h"
- #include "SampleMaster.h"
- #include "CompileOptions.h"
- #include "ORANGE/Parse/SimpleBatch.h"
- #include "GREEN/Mix/MixBuf.h"
- // try to hook the sound scaling tables for the palette
- ////////////////////////////////////////////////////////////////////////////////
- // Macros/types/etc.
- ////////////////////////////////////////////////////////////////////////////////
- #define EXIT_BG "credits/exit.bmp"
- // default credits parameters... (serve as emergency backups...)
- char g_szBackground[256] = "credits/pile640.bmp";
- char g_szCredits[256] = "credits/credits.txt";
- SampleMasterID* g_psmidMusic = &g_smidCreditsMusak;
- #define BG_X (g_pimScreenBuf->m_sWidth / 2 - pimBackground->m_sWidth / 2)
- #define BG_Y (g_pimScreenBuf->m_sHeight / 2 - pimBackground->m_sHeight / 2)
- #define CREDIT_TIME 30000
- #define LEFT_X 200
- #define SPACE_Y 30
- #define MUSAK_START_TIME 0
- #define MUSAK_END_TIME 0
- #define MIN_SCOLL_FRAME_MILLI 14 // Cap at 40 fps
- extern int wideScreenWidth;
- ////////////////////////////////////////////////////////////////////////////////
- // Variables/data
- ////////////////////////////////////////////////////////////////////////////////
- static SampleMaster::SoundInstance ms_siMusak;
- ////////////////////////////////////////////////////////////////////////////////
- // Function prototypes
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- // Forward Declarations
- ////////////////////////////////////////////////////////////////////////////////
- #define MAX_BACKGROUNDS 10
- class CBackgroundChange
- {
- public:
- RImage* m_pimPrevBackground;
- RImage* m_pimNewBackground;
- short m_sImageCacheIndex;
- char m_szNewName[64]; // resource name
- bool m_bActive;
- // All times in milliseconds...
- long m_lActivationTime; // also delay time
- long m_lFadeOutTime; // also in delta time form
- long m_lBlackTime; // also in delta time form
- long m_lFadeInTime; // also in delta time form
- UCHAR m_TransitionPalette[1024];
- typedef enum { Inactive,FadeOut,Black,FadeIn } BackState;
- BackState m_eState;
- typedef enum { OnEnter,OnExit } ActivationType;
- ActivationType m_eType;
- //--------------------------------------------------------
- void Clear()
- {
- m_pimPrevBackground = m_pimNewBackground = NULL;
- m_szNewName[0] = 0;
- m_bActive = false;
- m_lActivationTime = m_lFadeOutTime = m_lBlackTime = m_lFadeInTime = 0;
- m_eState = Inactive;
- m_sImageCacheIndex = -1;
- m_eType = OnEnter;
- }
- CBackgroundChange()
- {
- Clear();
- }
- ~CBackgroundChange()
- {
- Clear();
- }
- //--------------------------------------------------------
- void Activate(RImage* pimCurBack,RImage* pBackgrounds[])
- {
- // set current times as delta from current:
- m_lActivationTime += rspGetMilliseconds();
- m_lFadeOutTime += m_lActivationTime;
- m_lBlackTime += m_lFadeOutTime;
- m_lFadeInTime += m_lBlackTime;
- m_pimPrevBackground = pimCurBack;
- m_pimNewBackground = pBackgrounds[m_sImageCacheIndex];
- if (!m_pimNewBackground) m_pimNewBackground = pimCurBack;
- m_eState = FadeOut;
- }
- };
- class CTextPhrase
- {
- public:
- short m_sColorIndex;
- short m_sFontSize;
- short m_sLocalX;
- short m_sLocalY;
- typedef enum {Left, Right, Center} Justify;
- Justify m_eJust;
- char m_szText[128];
- CTextPhrase* m_pNext;
- CTextPhrase* m_pPrev;
- //------------------------------
- CTextPhrase()
- {
- m_pNext = m_pPrev = NULL;
- m_sFontSize = 0; // means use previous font size
- }
- ~CTextPhrase()
- {
- m_pNext = m_pPrev = NULL;;
- }
- };
- // Will actually create an image of itself
- //
- class CTextChunk
- {
- public:
- long m_lNumPhrases;
- CTextPhrase m_tHead; // bookends
- CTextPhrase m_tTail;
- short m_sGlobalTopY;
- short m_sGlobalBottomY;
- RImage* m_pimCache;
- CTextChunk* m_pNext;
- CTextChunk* m_pPrev;
- CBackgroundChange* m_pChangeBackground;
- //--------------------------
- CTextChunk()
- {
- m_lNumPhrases = 0;
- m_tHead.m_pNext = &m_tTail;
- m_tTail.m_pPrev = &m_tHead;
- m_sGlobalBottomY = -1;
- m_pimCache = NULL;
- m_pChangeBackground = NULL;
- }
- ~CTextChunk()
- {
- CTextPhrase* pCur = m_tHead.m_pNext;
- while (pCur != &m_tTail)
- {
- CTextPhrase* pNext = pCur->m_pNext;
- delete pCur;
- pCur = pNext;
- }
- if (m_pimCache)
- {
- delete m_pimCache;
- m_pimCache = NULL;
- }
- }
- //--------------------------
- // Must insert at tail to maintain order
- void AddPhrase(CTextPhrase* pNew)
- {
- m_lNumPhrases++;
- pNew->m_pNext = &m_tTail;
- pNew->m_pPrev = m_tTail.m_pPrev;
- m_tTail.m_pPrev->m_pNext = pNew;
- m_tTail.m_pPrev = pNew;
- }
- // WILL NOT DELETE!
- void RemovePhrase(CTextPhrase* pGone)
- {
- m_lNumPhrases--;
- pGone->m_pPrev->m_pNext = pGone->m_pNext;
- pGone->m_pNext->m_pPrev = pGone->m_pPrev;
- pGone->m_pNext = pGone->m_pPrev = NULL;
- }
- //------------------------------------
- void RenderChunk(short sW,RPrint* pPrint)
- {
- if (m_pimCache)
- {
- //TRACE("Already rendered\n");// legal!
- return;
- }
- m_pimCache = new RImage;
- m_pimCache->CreateImage(sW,m_sGlobalBottomY - m_sGlobalTopY+1,RImage::BMP8);
- CTextPhrase* pCur = m_tHead.m_pNext;
- pPrint->SetDestination(m_pimCache);
- while (pCur != &m_tTail)
- {
- //---------------------------------
- pPrint->SetColor(pCur->m_sColorIndex);
-
- // HARD CODED shadow colors (postal specific:)
- if (pCur->m_sColorIndex == 245) pPrint->SetColor(pCur->m_sColorIndex, 0 , 244);
- else pPrint->SetColor(pCur->m_sColorIndex, 0 , 243); // until we have comand support
-
- if (pCur->m_sFontSize) pPrint->SetFont(pCur->m_sFontSize);
- short sTabX = pCur->m_sLocalX;
- if (sTabX < 0) sTabX += sW; // from the right...
- // each justification needed to select the RPrint cell to use:
- // RPrint doesn't seem to be justifying correctly...
- // I will attempt some of my own:
- int wideScreenOffset = (wideScreenWidth - 640);
- switch (pCur->m_eJust)
- {
- short sRadius;
- //--------------------------- Left Justify
- case CTextPhrase::Left:
- pPrint->SetJustifyLeft();
- pPrint->SetColumn(0 ,0,sW,m_pimCache->m_sHeight);
- pPrint->print(sTabX + wideScreenOffset/2,pCur->m_sLocalY,"%s",pCur->m_szText);
- break;
- //--------------------------- Right Justify
- case CTextPhrase::Right:
- pPrint->SetJustifyRight();
- pPrint->SetColumn(0,0,sTabX + 1 + wideScreenOffset/2,m_pimCache->m_sHeight);
- // trick print into thinking it's a new line!
- pPrint->print(-1,pCur->m_sLocalY,"%s",pCur->m_szText);
- break;
- //--------------------------- Center Justify (about tab)
- case CTextPhrase::Center:
- pPrint->SetJustifyCenter();
- sRadius = MIN(sTabX,short(sW - sTabX));
- pPrint->SetColumn(sTabX - sRadius + wideScreenOffset,0,
- sRadius<<1, m_pimCache->m_sHeight);
- // trick print into thinking it's a new line!
- pPrint->print(-1,pCur->m_sLocalY,"%s",pCur->m_szText);
- break;
- }
-
- // undo justification:
- pPrint->SetColumn(0,0,sW,m_pimCache->m_sHeight);
- //---------------------------------
- pCur = pCur->m_pNext;
- }
- // Now compress it for speed!
- m_pimCache->Convert(RImage::FSPR8); // for testing.
- }
- void FreeChunk()
- {
- // Keep 'em for now...
- if (m_pimCache) delete m_pimCache;
- m_pimCache = NULL;
- }
- };
- char* pct = g_szCredits;
- extern void SetAll();
- // The highest level:
- class CScrollMaster
- {
- public:
- long m_lGlobalHeight;
- long m_lCurrentTopY;
- long m_lCurrentBottomY;
- long m_lTotalChunks;
- CTextChunk* m_pTopActiveChunk;
- CTextChunk* m_pBottomActiveChunk;
- long m_lActivationTime;
- RRect m_rDisplay;
- double m_dScrollRate; // screens/sec
- CTextChunk m_cHead; // bookends:
- CTextChunk m_cTail;
- short m_sNumBackgrounds;
- char m_szBackgroundNames[MAX_BACKGROUNDS][64];
- RImage* m_pimBackgrounds[MAX_BACKGROUNDS];
- CBackgroundChange* m_pCurSceneChange;
- //--------------------------------------
- CScrollMaster()
- {
- m_lGlobalHeight = 0;
- m_lCurrentBottomY = 0;
- m_lTotalChunks = 0;
- m_pTopActiveChunk = NULL;
- m_pBottomActiveChunk = NULL;
- m_lActivationTime = 0;
- m_cHead.m_pNext = &m_cTail;
- m_cTail.m_pPrev = &m_cHead;
- m_rDisplay = RRect(0,40,wideScreenWidth,360);
- m_dScrollRate = 0.1; // 100 seconds per screen
- m_sNumBackgrounds = 0;
- m_pCurSceneChange = NULL;
- }
- ~CScrollMaster()
- {
- CTextChunk* pCur = m_cHead.m_pNext;
- while (pCur != &m_cTail)
- {
- CTextChunk* pNext = pCur->m_pNext;
- delete pCur;
- pCur = pNext;
- }
- // release all of the backgrounds:
- short i;
- for (i = 0; i < m_sNumBackgrounds;i++)
- {
- if (m_pimBackgrounds[i]) g_resmgrShell.Release(m_pimBackgrounds[i]);
- m_pimBackgrounds[i] = NULL;
- }
- }
- void Configure(double dScrollRate,RRect* prWindow = NULL)
- {
- if (dScrollRate > 0.0) m_dScrollRate = dScrollRate;
- if (prWindow) m_rDisplay = *prWindow;
- }
- //--------------------------------
- void AddChunk(CTextChunk* pNew)
- {
- m_lTotalChunks++;
- pNew->m_pNext = &m_cTail;
- pNew->m_pPrev = m_cTail.m_pPrev;
- m_cTail.m_pPrev->m_pNext = pNew;
- m_cTail.m_pPrev = pNew;
- m_lGlobalHeight = pNew->m_sGlobalBottomY + 1;
- }
- //--------------------------------
- void Start(RPrint* pPrint)
- {
- // Try to load all the extra bmps from memory:
- short i;
- for (i=0; i < m_sNumBackgrounds;i++)
- {
- if (rspGetResource(&g_resmgrShell,m_szBackgroundNames[i],&m_pimBackgrounds[i])
- != SUCCESS)
- {
- TRACE("Couldn't load resource %s\n",m_szBackgroundNames[i]);
- m_pimBackgrounds[i] = NULL;
- }
- }
- // Activate first chunk:
- ASSERT(m_lTotalChunks >= 1);
- m_pTopActiveChunk = m_pBottomActiveChunk = m_cHead.m_pNext;
- m_pBottomActiveChunk->RenderChunk(m_rDisplay.sW,pPrint);
- m_pBottomActiveChunk = m_pBottomActiveChunk->m_pNext; // chunk 2
- // ATTEMPT TO LOAD ALL THE BACKGROUND RESOURCES FOR SCENE CHANGES!
- m_lActivationTime = rspGetMilliseconds();
- }
- // will return FAILURE if scroll is over!
- short Update(RPrint* pPrint)
- {
- // calculate current global scroll location:
- m_lCurrentBottomY = long(double(rspGetMilliseconds() - m_lActivationTime)
- * m_dScrollRate * m_rDisplay.sH / 1000.0);
- m_lCurrentTopY = (m_lCurrentBottomY - m_rDisplay.sH);
- if (m_lCurrentTopY > m_lGlobalHeight) return FAILURE; // scroll over!
- // see if we need to activate a new chunk:
- if (m_pBottomActiveChunk != &m_cTail)
- {
- if (m_pBottomActiveChunk->m_sGlobalTopY <= m_lCurrentBottomY)
- {
- m_pBottomActiveChunk->RenderChunk(m_rDisplay.sW,pPrint);
- m_pBottomActiveChunk = m_pBottomActiveChunk->m_pNext;
- // CHECK for scene change
- }
- }
- // see if we need to deactivate a new chunk:
- if (m_pTopActiveChunk != &m_cTail)
- {
- if (m_pTopActiveChunk->m_sGlobalBottomY <= m_lCurrentTopY)
- {
- m_pTopActiveChunk->FreeChunk();
- m_pTopActiveChunk = m_pTopActiveChunk->m_pNext;
- // CHECK for exit scene change
- }
- }
- return SUCCESS;
- }
- // will overlay the text onto your bitmap with the designated clip rectangle:
- // NOTE: script coordinates are relative to upper left clipping corner...
- void Render(RImage* pimDst)
- {
- // Draw each chunk separately:
- CTextChunk* pCur;
- // all active chunks should be pre-rendered:
- for (pCur = m_pTopActiveChunk; pCur != m_pBottomActiveChunk->m_pNext;
- pCur = pCur->m_pNext)
- {
- if (pCur != &m_cTail)
- {
- // Draw the pre-rendered chunk...
- if (pCur->m_pimCache)
- {
- rspBlit(pCur->m_pimCache,pimDst,m_rDisplay.sX,
- pCur->m_sGlobalTopY - m_lCurrentTopY
- + m_rDisplay.sY,&m_rDisplay);
- }
- }
- }
- }
- //-------------------------------------------------------------
- // returns the index number for the resource bmp:
- short AddBackground(char* pszName)
- {
- ASSERT(pszName);
- ASSERT(m_sNumBackgrounds < MAX_BACKGROUNDS);
- strcpy(m_szBackgroundNames[m_sNumBackgrounds],pszName);
- m_pimBackgrounds[m_sNumBackgrounds] = NULL;
- return m_sNumBackgrounds++;
- }
- };
- extern short sLoaded;
- ////////////////////////////////////////////////////////////////////////////////
- // This is cheesy, but right now I'm using a global stream to load into.
- ////////////////////////////////////////////////////////////////////////////////
- //CScrollMaster* gpCurStream = NULL;
- // For Res managing an ANSI file:
- class CFileTextInput
- {
- public:
- RBatch m_bf;
- //-----------------------
- CFileTextInput()
- {
- m_pStream = NULL;
- };
- ~CFileTextInput()
- {
- m_bf.clear(); // don't let it close the file!
- if (m_pStream) delete m_pStream;
- };
- //-----------------------
- short ParseTextInput(FILE* fp);
- //-----------------------
- short Load(RFile* pFile) // so res manager can hook it!
- {
- FILE* fp = pFile->m_fs;
- //--------------------- do my load:
- ParseTextInput(fp);
- return SUCCESS;
- }
- short Load(FILE* fp) // so res manager can hook it!
- {
- //--------------------- do my load:
- ParseTextInput(fp);
- return SUCCESS;
- }
- CScrollMaster* m_pStream;
- };
- ////////////////////////////////////////////////////////////////////////////////
- // Tokenizing the script file into absolute strips:
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- // ASSUME A VALID FILE STREAM
- //
- // This will parse and tokenize the incoming text...
- // It will not actually render it.
- //
- ////////////////////////////////////////////////////////////////////////////////
- short CFileTextInput::ParseTextInput(FILE* fp)
- {
- if (m_pStream)
- {
- TRACE("CFileTextInput::ParseTextInput: Stream in progress.\n");
- return FAILURE;
- }
- else
- m_pStream = new CScrollMaster; // needs to be freed!
- // We need to be a little low level so we can force feed a
- // file pointer to it.
- m_bf.clear();
- m_bf.m_fp = fp;
- m_bf.configure(" \t,;=({[",";/)}]",'`','/');
- char* pszToken;
- //gpCurStream = new CTextStream;
- short sGlobalY = 0;
- short sLocalY = 0;
- short sCurStripTop = 0;
- short sMaxH = 0;
- bool bNewChunk = true;
-
- short sCurFontSize = 0;
- short sCurTabX = 0;
- CTextPhrase::Justify eCurJust = CTextPhrase::Left;
- short sCurColor = 255;
- CTextChunk* pChunk = new CTextChunk;
- CTextPhrase* pCurPhrase = new CTextPhrase;
- pChunk->m_sGlobalTopY = sCurStripTop;
- pChunk->m_sGlobalBottomY = sCurStripTop;
- if (sLoaded) SetAll();
- while ((pszToken = m_bf.NextToken()) != NULL)
- {
- //TRACE("TOKEN = '%s'\n",pszToken);
- //-----------------------------------------------------
- if (!strcmp(pszToken,"color"))
- {
- sCurColor = atoi(m_bf.NextToken());
- continue;
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken,"size"))
- {
- pCurPhrase->m_sFontSize = 0;
- short sNewSize = atoi(m_bf.NextToken());
- // If we are starting a new chunk, we MUST give a font
- // size!
- if (bNewChunk || (sCurFontSize != sNewSize))
- {
- pCurPhrase->m_sFontSize = sNewSize;
- }
- sCurFontSize = sNewSize;
- bNewChunk = false;
- sMaxH = MAX(sMaxH,short(sLocalY + sNewSize));
- continue;
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken,"back"))
- {
- sLocalY -= atoi(m_bf.NextToken());
- if (sLocalY < 0)
- {
- TRACE("ERROR - you backed up above the strip!\n");
- sLocalY = 0;
- }
- continue;
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken+1,"tab"))
- {
- pCurPhrase->m_sLocalX = sCurTabX = atoi(m_bf.NextToken());
- switch (*pszToken)
- {
- case 'l': eCurJust = pCurPhrase->m_eJust = CTextPhrase::Left; break;
- case 'r': eCurJust = pCurPhrase->m_eJust = CTextPhrase::Right; break;
- case 'c': eCurJust = pCurPhrase->m_eJust = CTextPhrase::Center; break;
- }
- continue;
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken,";")) // means new line (& should benew phrase)
- {
- sLocalY += sCurFontSize;
- sMaxH = MAX(sMaxH,short(sLocalY + sCurFontSize));
- continue;
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken,"end")) // if in the sak, no EOF!
- {
- break; // done
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken,"skip")) // signals a new chunk!
- {
- //TRACE("New chunk!\n");
- bNewChunk = true;
- sMaxH = MAX(sMaxH,short(sLocalY + sCurFontSize));
- // Figure out how big chunk was:
- sGlobalY += MAX(sMaxH,sLocalY);
- pChunk->m_sGlobalBottomY = sGlobalY - 1;
- if (pChunk->m_sGlobalBottomY > pChunk->m_sGlobalTopY)
- {
- m_pStream->AddChunk(pChunk);
- }
- // create a new chunk
- short sVal = atoi(m_bf.NextToken());
- sGlobalY += sVal;
- pChunk = new CTextChunk;
- pChunk->m_sGlobalTopY = pChunk->m_sGlobalBottomY = sGlobalY;
- sMaxH = 0; // resetting stuff like this!
- sLocalY = 0;
- continue;
- }
- //-----------------------------------------------------
- if (!strcmp(pszToken,"scene")) // describe a scene change:
- {
- // first, parse through it all, then validate the information:
- // Good standards: (in milliseconds)
- short sDelay = 0,sFadeInTime = 1000,sFadeOutTime = 1000;
- short sBlackTime = 0, sOnExit = FALSE;
- char szName[64] = {0,};
- // The order doesn't matter - go until ')'
- pszToken = m_bf.NextToken();
- while (strcmp(pszToken,")")) // until we hit a right parenthesis
- {
- if (!strcmp(pszToken,"delay"))
- {
- sDelay = atoi(m_bf.NextToken());
- }
- else if (!strcmp(pszToken,"black"))
- {
- sBlackTime = atoi(m_bf.NextToken());
- }
- else if (!strcmp(pszToken,"out"))
- {
- sFadeOutTime = atoi(m_bf.NextToken());
- }
- else if (!strcmp(pszToken,"in"))
- {
- sFadeInTime = atoi(m_bf.NextToken());
- }
- else if (!strcmp(pszToken,"exit"))
- {
- sOnExit = TRUE;
- }
- else if (!strcmp(pszToken,"name"))
- {
- strcpy(szName,m_bf.NextToken());
- }
- pszToken = m_bf.NextToken();
- }
- //........... Now put the data into a useful form
- // and log it:
- CBackgroundChange* pNew = new CBackgroundChange;
- pNew->m_lActivationTime = sDelay;
- pNew->m_lFadeOutTime = sFadeOutTime;
- pNew->m_lBlackTime = sBlackTime;
- pNew->m_lFadeInTime = sFadeInTime;
- strcpy(pNew->m_szNewName,szName);
- if (sOnExit) pNew->m_eType = CBackgroundChange::OnExit;
- // Log into the stream:
- pNew->m_sImageCacheIndex = m_pStream->AddBackground(szName);
- // Add into chunk:
- ASSERT(!pChunk->m_pChangeBackground);
- pChunk->m_pChangeBackground = pNew;
- continue;
- }
- //-----------------------------------------------------
- // Assume default case is text to be printed, which
- // also signals the creation of a new phrase...
- //-----------------------------------------------------
- if (*pCurPhrase->m_szText)
- {
- TRACE("Error - already text\n");
- }
- // Set latest states
- pCurPhrase->m_sLocalY = sLocalY;
- pCurPhrase->m_sColorIndex = sCurColor;
- strcpy(pCurPhrase->m_szText,pszToken);
- // Create a brand new phrase:
- pChunk->AddPhrase(pCurPhrase);
- CTextPhrase* pNewPhrase = new CTextPhrase;
- *pNewPhrase = *pCurPhrase; // struct copy
- *pNewPhrase->m_szText = 0;
- pCurPhrase = pNewPhrase;
- continue;
- }
- if (pChunk)
- {
- // Figure out how big the chunk was
- sGlobalY += MAX(sMaxH,sLocalY);
- pChunk->m_sGlobalBottomY = sGlobalY - 1;
- m_pStream->AddChunk(pChunk);
- }
- if (pCurPhrase)
- {
- delete pCurPhrase;
- pCurPhrase = NULL;
- }
- return SUCCESS;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // General scrolling text screens: Returns FAILURE if assets couldn't load
- // OR returns FAILURE if use aborts!
- //
- // All resources are assumed from the shell sak.
- //
- ////////////////////////////////////////////////////////////////////////////////
- short ScrollPage(char* pszBackground,char* pszScrollScript,double dScrollRate,RRect *prWindow)
- {
- // Try to load resources:
- short sResult;
- rspLockBuffer();
- // clear background BEFORE doing a palette swap:
- rspRect(RSP_BLACK_INDEX,g_pimScreenBuf,0,0,g_pimScreenBuf->m_sWidth,
- g_pimScreenBuf->m_sHeight);
- rspUnlockBuffer();
- rspUpdateDisplay();
- // Load background
- RImage* pimBackground;
- if (rspGetResource(&g_resmgrShell, pszBackground, &pimBackground) != SUCCESS)
- {
- TRACE("ScrollPage: Couldn't load background %s\n",pszBackground);
- return FAILURE; // couldn't load background
- }
- // Set palette
- ASSERT(pimBackground->m_pPalette != NULL);
- ASSERT(pimBackground->m_pPalette->m_type == RPal::PDIB);
- rspSetPaletteEntries(
- 0, //10,
- 256, // 236,
- pimBackground->m_pPalette->Red(0), //10
- pimBackground->m_pPalette->Green(0), //10
- pimBackground->m_pPalette->Blue(0), //10
- pimBackground->m_pPalette->m_sPalEntrySize);
- rspUpdatePalette();
- // Load text script:
- CFileTextInput* pScript = NULL; // must free it myself!
- // Try to override with our own file, because I'm too lazy to figure out how to regenerate .sak files.
- FILE *nonsak = fopen(FindCorrectFile("res/credits.txt", "rb"), "rb");
- if (nonsak != NULL)
- {
- pScript = new CFileTextInput;
- pScript->Load(nonsak);
- }
- if (pScript == NULL)
- {
- sResult = rspGetResource(&g_resmgrShell, pszScrollScript, &pScript);
- if (sResult != SUCCESS)
- {
- // try another sak:
- sResult = rspGetResource(&g_resmgrSamples, pszScrollScript, &pScript);
- if (sResult != SUCCESS)
- {
- TRACE("ScrollPage: Couldn't load script %s\n",pszScrollScript);
- g_resmgrShell.Release(pimBackground); // dom't need it anymore
- return FAILURE; // couldn't load background
- }
- }
- }
- // Set standard font...
- RPrint print;
- print.SetFont(24, &g_fontPostal);
- print.SetColor(255, 0 , 0);
- print.SetEffectAbs(RPrint::SHADOW_X,1);
- print.SetEffectAbs(RPrint::SHADOW_Y,1);
- // Clear mouse and keyboard events
- rspClearKeyEvents();
- rspClearMouseEvents();
- // Clear screen
- rspLockBuffer();
- rspRect(RSP_BLACK_INDEX, g_pimScreenBuf, 0, 0, g_pimScreenBuf->m_sWidth, g_pimScreenBuf->m_sHeight);
- rspUnlockBuffer();
- pScript->m_pStream->Configure(dScrollRate,prWindow);
- pScript->m_pStream->Start(&print);
- // Wait until user input
- long lKey = 0;
- short sButtons = 0;
- short sJoyPress = 0;
- //****************** STATISTICAL ANALYSIS!
- /*
- long lTimeCount[256] = {0,}; // bucket sort
- */
- long lRunningTime,lPrevTime;
- lRunningTime = lPrevTime = rspGetMilliseconds();
- while ( (pScript->m_pStream->Update(&print) == SUCCESS) && !lKey && !sButtons && !(rspGetQuitStatus()) && !sJoyPress)
- {
- // Show title image.
- rspLockBuffer();
- rspBlit(
- pimBackground,
- g_pimScreenBuf,
- 0,0,
- BG_X ,//+ (rspGetMilliseconds()/100)&15,
- BG_Y,
- pimBackground->m_sWidth,
- pimBackground->m_sHeight);
- pScript->m_pStream->Render(g_pimScreenBuf);
- rspUnlockBuffer();
- rspUpdateDisplay();
- UpdateSystem();
- // Get key and mouse button inputs
- rspGetMouse(NULL, NULL, &sButtons);
- rspGetKey(&lKey);
- sJoyPress = IsXInputButtonPressed();
- // Clear mouse events to avoid overflowing the queue
- rspClearMouseEvents();
- // Restrict the frame rate to MAX_SCOLL_FRAME_MILLI
- while ( (lRunningTime - lPrevTime) < MIN_SCOLL_FRAME_MILLI)
- {
- lRunningTime = rspGetMilliseconds();
- }
- //*******************8 Update timing statistics:
- //lTimeCount[lRunningTime - lPrevTime]++;
- lPrevTime = lRunningTime;
- }
- //************* Report statistics
- /*
- FILE* fp = fopen("speed.out","a");
- for (short i=0;i < 256;i++) fprintf(fp,"%hd = %ld\n",i,lTimeCount[i]);
- */
- //------------------------------------------------------------------------------
- // palette fade out ? ...
- // Free resources:
- g_resmgrShell.Release(pimBackground);
- if (nonsak != NULL)
- {
- delete pScript;
- fclose(nonsak);
- }
- else
- {
- g_resmgrShell.Release(pScript);
- }
- // Clean Up:
- // Clear mouse and keyboard events
- rspClearKeyEvents();
- rspClearMouseEvents();
- // DO NOT Clear screen!
- /*
- rspLockBuffer();
- rspRect(RSP_BLACK_INDEX, g_pimScreenBuf, 0, 0, g_pimScreenBuf->m_sWidth, g_pimScreenBuf->m_sHeight);
- rspUnlockBuffer();
- */
- rspUpdateDisplay();
- if (lKey || sButtons || sJoyPress || rspGetQuitStatus()) return FAILURE;
- return SUCCESS;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Display the credits - now with variable input
- //
- ////////////////////////////////////////////////////////////////////////////////
- // Returns 0 if successfull, non-zero otherwise
- short Credits(SampleMasterID* pMusic,
- char* pszBackground,
- char* pszCredits)
- {
- short sResult = 0;
- #ifdef SHOW_EXIT_SCREEN
-
- RImage* pimBackground;
- sResult = rspGetResource(&g_resmgrShell, EXIT_BG, &pimBackground);
- if (sResult == 0)
- {
- // Set palette
- ASSERT(pimBackground->m_pPalette != NULL);
- ASSERT(pimBackground->m_pPalette->m_type == RPal::PDIB);
- rspSetPaletteEntries(
- 0, //10,
- 256, // 236,
- pimBackground->m_pPalette->Red(0), //10
- pimBackground->m_pPalette->Green(0), //10
- pimBackground->m_pPalette->Blue(0), //10
- pimBackground->m_pPalette->m_sPalEntrySize);
- rspUpdatePalette();
- // Show title image.
- rspLockBuffer();
- rspBlit(
- pimBackground,
- g_pimScreenBuf,
- 0, 0,
- BG_X,
- BG_Y,
- pimBackground->m_sWidth,
- pimBackground->m_sHeight);
- rspUnlockBuffer();
- }
- rspUpdateDisplay();
- // Wait a while or until user input
- long lKey = 0;
- short sButtons = 0;
- do {
- UpdateSystem();
- // Get key and mouse button inputs
- short sButtons;
- rspGetMouse(NULL, NULL, &sButtons);
- rspGetKey(&lKey);
- // Clear mouse events to avoid overflowing the queue
- rspClearMouseEvents();
- } while (!lKey && !sButtons && rspGetQuitStatus() == FALSE);
- // Release bg
- g_resmgrShell.Release(pimBackground);
- #else
- SampleMasterID* psmidMusic;
- char szBackground[256];
- char szCredits[256];
- // Set defaults:
- psmidMusic = g_psmidMusic;
- strcpy(szBackground,g_szBackground);
- strcpy(szCredits,g_szCredits);
- // Set input parameters:
- if (pMusic) psmidMusic = pMusic;
- if (pszBackground) strcpy(szBackground,pszBackground);
- if (pszCredits) strcpy(szCredits,pszCredits);
- // Start credits music
- PlaySample( // Returns nothing.
- // Does not fail.
- *psmidMusic, // In: Identifier of sample you want played.
- SampleMaster::Unspecified, // In: Sound Volume Category for user adjustment
- 255, // In: Initial Sound Volume (0 - 255)
- &ms_siMusak, // Out: Handle for adjusting sound volume
- NULL, // Out: Sample duration in ms, if not NULL.
- MUSAK_START_TIME, // In: Where to loop back to in milliseconds.
- // -1 indicates no looping (unless m_sLoop is
- // explicitly set).
- MUSAK_END_TIME, // In: Where to loop back from in milliseconds.
- // In: If less than 1, the end + lLoopEndTime is used.
- true); // In: Call ReleaseAndPurge rather than Release after playing
-
- //------------------------------------------------------------------------------
- // Begin scrolling loop....
- RRect rect(0,80,wideScreenWidth,320);
- if (ScrollPage(szBackground,szCredits,0.12,&rect) != SUCCESS)
- {
- // USER aborted!
- // Stop the musak
- if (ms_siMusak)
- {
- // Don't just allow it to finish.
- StopLoopingSample(ms_siMusak);
- // Cut it off.
- AbortSample(ms_siMusak);
- // Clear.
- ms_siMusak = 0;
- // Play final sample that completes the cut off sound. ***
- }
- return SUCCESS;
- }
- // fade out the musak: cross fade the laughter
- SampleMaster::SoundInstance siLaughter;
- UnlockAchievement(ACHIEVEMENT_WATCH_ALL_CREDITS);
- // Start silent laughter looping:
- PlaySample(
- g_smidDemonLaugh2,
- SampleMaster::Unspecified,
- 0,
- &siLaughter,
- NULL,
- 0,
- 0,
- true);
- long lTimeToFade = 15000;
- long lStartTime = rspGetMilliseconds();
- // Copy the palette:
- UCHAR PaletteCopy[256 * 3] = {0,};
-
- rspGetPaletteEntries(10,236,PaletteCopy+30,PaletteCopy + 31,PaletteCopy + 32,3);
- //====================================================================
- long lCurTime;
- while ( (lCurTime = rspGetMilliseconds() - lStartTime) < lTimeToFade)
- {
- short sByteLevel = short((255.0 * lCurTime) / lTimeToFade);
- if (sByteLevel > 255) sByteLevel = 255;
- // Update the sound volumes:
- SetInstanceVolume(ms_siMusak,255 - sByteLevel);
- SetInstanceVolume(siLaughter,sByteLevel);
- // Update the Palette:
- short i=0;
- short sCurPal = 10 * 3;
- for (i=10; i < 246; i++, sCurPal += 3)
- {
- rspSetPaletteEntry( i,
- (PaletteCopy[sCurPal + 0] * (256 - sByteLevel)) / 256,
- (PaletteCopy[sCurPal + 1] * (256 - sByteLevel)) / 256,
- (PaletteCopy[sCurPal + 2] * (256 - sByteLevel)) / 256
- );
- }
- rspUpdatePalette();
- UpdateSystem();
- }
- //====================================================================
- // Stop the musak
- if (ms_siMusak)
- {
- // Don't just allow it to finish.
- StopLoopingSample(ms_siMusak);
- }
- // Stop the musak
- if (siLaughter)
- {
- // Don't just allow it to finish.
- StopLoopingSample(siLaughter);
- }
- // Stop the musak
- if (ms_siMusak)
- {
- // Cut it off.
- AbortSample(ms_siMusak);
- // Clear.
- ms_siMusak = 0;
- // Play final sample that completes the cut off sound. ***
- }
- if (siLaughter)
- {
- while (IsSamplePlaying(siLaughter) == true)
- {
- UpdateSystem();
- }
- }
- //===========================================================================
- // Stop the musak
- if (siLaughter)
- {
- // Cut it off.
- AbortSample(siLaughter);
- // Clear.
- siLaughter = 0;
- // Play final sample that completes the cut off sound. ***
- }
- #endif
- return SUCCESS;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // EOF
- ////////////////////////////////////////////////////////////////////////////////
|