123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- 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. */
- #include "StdAfx.h"
- #include "LCDDrawing.h"
- extern CGame *_pGame;
- // console variables
- static const FLOAT tmConsoleFade = 0.0f; // how many seconds it takes console to fade in/out
- static FLOAT fConsoleFadeValue = 0.0f; // faded value of console (0..1)
- static CTimerValue tvConsoleLast;
- static CTString strConsole;
- static CTString strInputHistory = "\n";
- static CTString strEditingLine;
- static CTString strExpandStart;
- static CTString strLastExpanded;
- static CTString strCurrentLine;
- static BOOL bLastExpandedFound;
- static INDEX iSymbolOffset;
- static INDEX iHistoryLine=0;
- static INDEX iCursorPos=0;
- static INDEX ctConsoleLinesOnScreen;
- static INDEX con_iFirstLine = 1;
- extern FLOAT con_fHeightFactor;
- extern FLOAT con_tmLastLines;
- // find a line with given number in a multi-line string counting from end of string
- BOOL GetLineCountBackward(const char *pchrStringStart, const char *pchrStringEnd,
- INDEX iBackwardLine, CTString &strResult)
- {
- // start at the end of string
- const char *pchrCurrent = pchrStringEnd;
- INDEX ctLinesDone=0;
- // while line of given number is not found
- while(ctLinesDone!=iBackwardLine) {
- // go one character back
- pchrCurrent--;
- // if got before start of string
- if (pchrCurrent < pchrStringStart) {
- // line is not found
- return FALSE;
- }
- // if at line break
- if(*pchrCurrent == '\n') {
- // count lines
- ctLinesDone++;
- }
- }
- // check that pointer is not outside range
- ASSERT(pchrCurrent>=pchrStringStart && pchrCurrent<pchrStringEnd);
- // if exactly on line break, skip it
- if (*pchrCurrent=='\n') {
- pchrCurrent++;
- }
- // find end of that line
- const char *pchrLineEnd=strchr(pchrCurrent, '\r');
- if (pchrLineEnd==NULL) {
- pchrLineEnd = pchrStringEnd;
- }
- // copy the found line
- char achrLine[ 1024];
- strncpy( achrLine, pchrCurrent, pchrLineEnd-pchrCurrent);
- achrLine[ pchrLineEnd-pchrCurrent]=0;
- strResult = achrLine;
- return TRUE;
- }
- void CGame::ConsoleRender(CDrawPort *pdp)
- {
- if( _pGame->gm_csConsoleState==CS_OFF) {
- con_iFirstLine = 1;
- tvConsoleLast = _pTimer->GetHighPrecisionTimer();
- return;
- }
- // get console height
- con_fHeightFactor = Clamp( con_fHeightFactor, 0.1f, 1.0f);
- FLOAT fHeightFactor = con_fHeightFactor;
- if( !gm_bGameOn) fHeightFactor = 0.9f;
- // calculate up-down speed to be independent of refresh speed
- CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
- CTimerValue tvDelta = tvNow - tvConsoleLast;
- tvConsoleLast = tvNow;
- FLOAT fFadeSpeed = (FLOAT)(tvDelta.GetSeconds() / tmConsoleFade);
- // if console is dropping down
- if( _pGame->gm_csConsoleState==CS_TURNINGON) {
- // move it down
- fConsoleFadeValue += fFadeSpeed;
- // if finished moving
- if( fConsoleFadeValue>1.0f) {
- // stop
- fConsoleFadeValue = 1.0f;
- _pGame->gm_csConsoleState = CS_ON;
- }
- }
- // if console is pulling up
- if( _pGame->gm_csConsoleState==CS_TURNINGOFF) {
- // move it up
- fConsoleFadeValue -= fFadeSpeed;
- // if finished moving
- if( fConsoleFadeValue<0.0f) {
- // stop
- fConsoleFadeValue = 0.0f;
- _pGame->gm_csConsoleState = CS_OFF;
- // if not in network
- if (!_pNetwork->IsNetworkEnabled()) {
- // don't show last lines on screen after exiting console
- CON_DiscardLastLineTimes();
- }
- return;
- }
- }
- if (_pGame->gm_csConsoleState==CS_TALK) {
- fHeightFactor = 0.1f;
- fConsoleFadeValue = 1.0f;
- }
- // calculate size of console box so that it covers upper half of the screen
- FLOAT fHeight = ClampUp( fHeightFactor*fConsoleFadeValue*2, fHeightFactor);
- CDrawPort dpConsole( pdp, 0.0f, 0.0f, 1.0f, fHeight);
- // lock drawport
- if( !dpConsole.Lock()) return;
- LCDPrepare(fConsoleFadeValue);
- LCDSetDrawport(&dpConsole);
- dpConsole.Fill(LCDFadedColor(C_BLACK|225));
- PIX pixSizeI = dpConsole.GetWidth();
- PIX pixSizeJ = dpConsole.GetHeight();
- COLOR colLight = LCDFadedColor(C_WHITE|255);
- COLOR colDark = LCDFadedColor(SE_COL_BLUE_LIGHT|255);
- INDEX iBackwardLine = con_iFirstLine;
- if( iBackwardLine>1) Swap( colLight, colDark);
- PIX pixLineSpacing = _pfdConsoleFont->fd_pixCharHeight + _pfdConsoleFont->fd_pixLineSpacing;
- LCDRenderCloudsForComp();
- //LCDRenderGrid();
- LCDRenderClouds2();
- dpConsole.DrawLine( 0, pixSizeJ-1, pixSizeI, pixSizeJ-1, LCDFadedColor(SE_COL_BLUE_NEUTRAL|255));
- const COLOR colFill = (colDark & ~CT_AMASK) | 0x2F;
- dpConsole.Fill( 0, pixSizeJ-pixLineSpacing*1.6f, pixSizeI, pixLineSpacing*1.6f, colFill);
- // setup font
- PIX pixTextX = (PIX)(dpConsole.GetWidth()*0.01f);
- PIX pixYLine = dpConsole.GetHeight()-14;
- dpConsole.SetFont( _pfdConsoleFont);
- // print editing line of text
- dpConsole.SetTextMode(-1);
- CTString strPrompt;
- if (_pGame->gm_csConsoleState == CS_TALK) {
- strPrompt = TRANS("say: ");
- } else {
- strPrompt = "=> ";
- }
- CTString strLineOnScreen = strPrompt + strEditingLine;
- dpConsole.PutText( strLineOnScreen, pixTextX, pixYLine, colLight);
- dpConsole.SetTextMode(+1);
- // add blinking cursor
- if( ((ULONG)(_pTimer->GetRealTimeTick()*2)) & 1) {
- CTString strCursor="_";
- FLOAT fTextScalingX = dpConsole.dp_fTextScaling * dpConsole.dp_fTextAspect;
- PIX pixCellSize = _pfdConsoleFont->fd_pixCharWidth * fTextScalingX + dpConsole.dp_pixTextCharSpacing;
- PIX pixCursorX = pixTextX + (iCursorPos+strlen(strPrompt))*pixCellSize;
- dpConsole.PutText( strCursor, pixCursorX, pixYLine+2, colDark);
- }
- // render previous outputs
- con_iFirstLine = ClampDn( con_iFirstLine, 1L);
- pixYLine -= (PIX)(pixLineSpacing * 1.333f);
- ctConsoleLinesOnScreen = pixYLine/pixLineSpacing;
- while( pixYLine >= 0) {
- CTString strLineOnScreen = CON_GetLastLine(iBackwardLine);
- dpConsole.PutText( strLineOnScreen, pixTextX, pixYLine, colDark);
- iBackwardLine++;
- pixYLine -= pixLineSpacing;
- }
- // all done
- dpConsole.Unlock();
- }
- // print last few lines from console to top of screen
- void CGame::ConsolePrintLastLines(CDrawPort *pdp)
- {
- // get number of lines to print
- con_tmLastLines = Clamp( con_tmLastLines, 1.0f, 10.0f);
- INDEX ctLines = CON_NumberOfLinesAfter( _pTimer->GetRealTimeTick() - con_tmLastLines);
- // if no lines left to print, just skip it
- if( ctLines==0) return;
- // setup font
- _pfdConsoleFont->SetFixedWidth();
- pdp->SetFont( _pfdConsoleFont);
- PIX pixCharHeight = _pfdConsoleFont->GetHeight() -1;
- // put some filter underneath for easier reading
- pdp->Fill( 0, 0, pdp->GetWidth(), pixCharHeight*ctLines, C_BLACK|128);
- // for each line
- for( INDEX iLine=0; iLine<ctLines; iLine++) {
- CTString strLine = CON_GetLastLine(iLine+1);
- pdp->PutText( strLine, 0, pixCharHeight*(ctLines-iLine-1), SE_COL_BLUE_LIGHT|255);
- }
- }
- static void Key_Backspace( BOOL bShift, BOOL bRight)
- {
- // do nothing if string is empty
- INDEX ctChars = strlen(strEditingLine);
- if( ctChars==0) return;
- if( bRight && iCursorPos<ctChars) { // DELETE key
- if( bShift) { // delete to end of line
- strEditingLine.TrimRight(iCursorPos);
- } else { // delete only one char
- strEditingLine.DeleteChar(iCursorPos);
- }
- }
- if( !bRight && iCursorPos>0) { // BACKSPACE key
- if( bShift) { // delete to start of line
- strEditingLine.TrimLeft(ctChars-iCursorPos);
- iCursorPos=0;
- } else { // delete only one char
- strEditingLine.DeleteChar(iCursorPos-1);
- iCursorPos--;
- }
- }
- }
- static void Key_ArrowUp(void)
- {
- CTString strSlash = "/";
- CTString strHistoryLine;
- if( iHistoryLine==0) strCurrentLine = strEditingLine;
- INDEX iCurrentHistoryLine = iHistoryLine;
- do {
- // determine previous line in history
- iCurrentHistoryLine++;
- const char *pchrHistoryStart = (const char*)strInputHistory;
- const char *pchrHistoryEnd = pchrHistoryStart +strlen( strInputHistory) -1;
- // we reach top of history, if line doesn't exist in history
- if( !GetLineCountBackward( pchrHistoryStart, pchrHistoryEnd, iCurrentHistoryLine, strHistoryLine)) return;
- } while( strCurrentLine!="" &&
- strnicmp( strHistoryLine, strCurrentLine, Min(strlen(strHistoryLine), strlen(strCurrentLine)))!=0 &&
- strnicmp( strHistoryLine, strSlash+strCurrentLine, Min(strlen(strHistoryLine), strlen(strCurrentLine)+1))!=0);
- // set new editing line
- iHistoryLine = iCurrentHistoryLine;
- strEditingLine = strHistoryLine;
- iCursorPos = strlen(strEditingLine);
- }
- static void Key_ArrowDown(void)
- {
- CTString strSlash = "/";
- CTString strHistoryLine;
- if( iHistoryLine==0) strCurrentLine = strEditingLine;
- INDEX iCurrentHistoryLine = iHistoryLine;
- while( iCurrentHistoryLine>1) {
- iCurrentHistoryLine--;
- const char *pchrHistoryStart = (const char *) strInputHistory;
- const char *pchrHistoryEnd = pchrHistoryStart +strlen(strInputHistory) -1;
- // line must exist in history
- BOOL bExists = GetLineCountBackward( pchrHistoryStart, pchrHistoryEnd, iCurrentHistoryLine, strHistoryLine);
- ASSERT( bExists);
- // set new editing line
- if( strCurrentLine=="" ||
- strnicmp( strHistoryLine, strCurrentLine, Min(strlen(strHistoryLine), strlen(strCurrentLine))) ==0 ||
- strnicmp( strHistoryLine, strSlash+strCurrentLine, Min(strlen(strHistoryLine), strlen(strCurrentLine)+1))==0) {
- iHistoryLine = iCurrentHistoryLine;
- strEditingLine = strHistoryLine;
- iCursorPos = strlen(strEditingLine);
- return;
- }
- }
- }
- void DoCheat(const CTString &strCommand, const CTString &strVar)
- {
- _pShell->SetINDEX(strVar, !_pShell->GetINDEX(strVar));
- BOOL bNew = _pShell->GetINDEX(strVar);
- CPrintF("%s: %s\n", strCommand, bNew?"ON":"OFF");
- }
- static void Key_Return(void)
- {
- // ignore keydown return (keyup will be handled) - because of key bind to return
- //if( _pGame->gm_csConsoleState==CS_TALK) return;
- // clear editing line from whitespaces
- strEditingLine.TrimSpacesLeft();
- strEditingLine.TrimSpacesRight();
- // reset display position
- con_iFirstLine = 1;
- // ignore empty lines
- if( strEditingLine=="" || strEditingLine=="/") {
- strEditingLine = "";
- iCursorPos = 0;
- return;
- }
- // add to history
- strInputHistory += strEditingLine +"\r\n";
- iHistoryLine = 0;
- // check for cheats
- #define CHEAT_PREFIX "please"
- if (strEditingLine.HasPrefix(CHEAT_PREFIX) || strEditingLine.HasPrefix("/" CHEAT_PREFIX)) {
- strEditingLine.RemovePrefix(CHEAT_PREFIX);
- strEditingLine.RemovePrefix("/ " CHEAT_PREFIX );
- strEditingLine.TrimSpacesLeft();
- if (strEditingLine=="god") {
- DoCheat(strEditingLine, "cht_bGod");
-
- } else if (strEditingLine=="giveall") {
- DoCheat(strEditingLine, "cht_bGiveAll");
-
- } else if (strEditingLine=="killall") {
- DoCheat(strEditingLine, "cht_bKillAll");
-
- } else if (strEditingLine=="open") {
- DoCheat(strEditingLine, "cht_bOpen");
-
- } else if (strEditingLine=="tellall") {
- DoCheat(strEditingLine, "cht_bAllMessages");
-
- } else if (strEditingLine=="fly") {
- DoCheat(strEditingLine, "cht_bFly");
- } else if (strEditingLine=="ghost") {
- DoCheat(strEditingLine, "cht_bGhost");
- } else if (strEditingLine=="invisible") {
- DoCheat(strEditingLine, "cht_bInvisible");
- } else if (strEditingLine=="refresh") {
- DoCheat(strEditingLine, "cht_bRefresh");
- } else {
- CPrintF("sorry?\n");
- }
- // parse editing line
- } else if( strEditingLine[0]=='/') {
- // add to output and execute
- CPrintF( "-> %s\n", strEditingLine);
- strEditingLine+=";";
- _pShell->Execute(strEditingLine+1);
- }
- else if( !_pGame->gm_bGameOn) {
- // add to output and execute
- CPrintF( "-> %s\n", strEditingLine);
- strEditingLine+=";";
- _pShell->Execute(strEditingLine);
- }
- else {
- // just send chat
- _pNetwork->SendChat(-1, -1, strEditingLine);
- }
- // reset editing line
- strEditingLine = "";
- iCursorPos = 0;
- }
- // find first character that is not part of a symbol, backwards
- char *strrnonsym(const char *strString)
- {
- const char *pch = strString+strlen(strString)-1;
- while( pch>=strString) {
- char ch = *pch;
- if( !isalnum(ch) && ch!='_') return (char*)pch;
- pch--;
- }
- return NULL;
- }
- static void Key_Tab( BOOL bShift)
- {
- // clear editing line from whitespaces
- strEditingLine.TrimSpacesLeft();
- strEditingLine.TrimSpacesRight();
- // eventualy prepend the command like with '/'
- if (strEditingLine[0]!='/') strEditingLine = CTString("/")+strEditingLine;
- // find symbol letter typed so far
- CTString strSymbol;
- CTString strLastThatCanBeExpanded;
- if( strLastExpanded == "") {
- strExpandStart = strEditingLine;
- iSymbolOffset = 0;
- char *pcLastSymbol = strrnonsym( strEditingLine);
- // remember symbol text and offset inside editing line
- if( pcLastSymbol!=NULL) {
- strExpandStart = pcLastSymbol+1;
- iSymbolOffset = (INDEX)(pcLastSymbol+1 - (const char*)strEditingLine);
- }
- // printout all symbols that matches (if not only one, and not TAB only)
- INDEX ctSymbolsFound=0;
- BOOL bFirstFound = FALSE;
- CTString strLastMatched;
- {FOREACHINDYNAMICARRAY( _pShell->sh_assSymbols, CShellSymbol, itss) {
- // TAB only pressd?
- if( strExpandStart=="") break;
- // get completion name if current symbol is for user
- if( !(itss->ss_ulFlags&SSF_USER)) continue;
- strSymbol = itss->GetCompletionString();
- // if this symbol can be expanded
- if( strnicmp( strSymbol, strExpandStart, Min(strlen(strSymbol),strlen(strExpandStart))) == 0) {
- // can we print last found symbol ?
- if( strLastMatched!="") {
- if( !bFirstFound) CPrintF( " -\n");
- CPrintF( " %s\n", strLastMatched);
- bFirstFound = TRUE;
- }
- strLastMatched = strSymbol;
- ctSymbolsFound++;
- }
- }}
- // print last symbol
- if( ctSymbolsFound>1) CPrintF( " %s\n", strLastMatched);
- }
- // for each of symbols in the shell
- bLastExpandedFound = FALSE;
- BOOL bTabSymbolFound = FALSE;
- {FOREACHINDYNAMICARRAY( _pShell->sh_assSymbols, CShellSymbol, itss)
- {
- // skip if it is not visible to user
- if( !(itss->ss_ulFlags&SSF_USER)) continue;
- // get completion name for that symbol
- strSymbol = itss->GetCompletionString();
- // if this symbol can be expanded
- if( strnicmp( strSymbol, strExpandStart, Min(strlen(strSymbol),strlen(strExpandStart))) == 0)
- {
- // at least one symbol is found, so tab will work
- bTabSymbolFound = TRUE;
- // if this is first time we are doing this
- if( strLastExpanded == "") {
- // remember symbol as last expanded and set it as current
- strLastExpanded = strSymbol;
- break;
- }
- // if last expanded was already found, set this symbol as result and remember it as last expanded
- if( bLastExpandedFound) {
- strLastExpanded = strSymbol;
- break;
- }
- // if last expanded was not found yet, check if this one is last expanded
- if( stricmp( strLastExpanded, strSymbol) == 0) {
- // if looping backward (Shift+Tab)
- if( bShift) {
- // if we can loop backwards
- if( strLastThatCanBeExpanded != "") {
- strLastExpanded = strLastThatCanBeExpanded;
- break;
- // act like no symbols are found
- } else {
- bTabSymbolFound = FALSE;
- break;
- }
- }
- // if so, mark it
- bLastExpandedFound = TRUE;
- }
- // remember current as last that can be expanded (for loopbing back)
- strLastThatCanBeExpanded = strSymbol;
- }
- }}
- // if symbol was found
- if( bTabSymbolFound) {
- // set it in current editing line
- *((char*)(const char*)strEditingLine +iSymbolOffset) = '\0';
- strEditingLine += strLastExpanded;
- }
- iCursorPos = strlen(strEditingLine);
- }
- static void Key_PgUp( BOOL bShift)
- {
- if( bShift) con_iFirstLine += ctConsoleLinesOnScreen;
- else con_iFirstLine++;
- }
- static void Key_PgDn( BOOL bShift)
- {
- if( bShift) con_iFirstLine -= ctConsoleLinesOnScreen;
- else con_iFirstLine--;
- con_iFirstLine = ClampDn( con_iFirstLine, 1L);
- }
- void CGame::ConsoleKeyDown( MSG msg)
- {
- // if console is off
- if (_pGame->gm_csConsoleState==CS_OFF || _pGame->gm_csConsoleState==CS_TURNINGOFF) {
- // do nothing
- return;
- }
- BOOL bShift = GetKeyState(VK_SHIFT) & 0x8000;
- switch( msg.wParam) {
- case VK_RETURN: Key_Return(); break;
- case VK_UP: Key_ArrowUp(); break;
- case VK_DOWN: Key_ArrowDown(); break;
- case VK_TAB: Key_Tab(bShift); break;
- case VK_PRIOR: Key_PgUp(bShift); break;
- case VK_NEXT: Key_PgDn(bShift); break;
- case VK_BACK: Key_Backspace(bShift, FALSE); break;
- case VK_DELETE: Key_Backspace(bShift, TRUE); break;
- case VK_LEFT: if( iCursorPos > 0) iCursorPos--; break;
- case VK_RIGHT: if( iCursorPos < strlen(strEditingLine)) iCursorPos++; break;
- case VK_HOME: iCursorPos = 0; break;
- case VK_END: iCursorPos = strlen(strEditingLine); break;
- }
- }
- void CGame::ConsoleChar( MSG msg)
- {
- // if console is off, do nothing
- if (_pGame->gm_csConsoleState==CS_OFF) return;
- // for all keys except tab and shift, discard last found tab browsing symbol
- char chrKey = msg.wParam;
- if( msg.wParam!=VK_TAB && msg.wParam!=VK_SHIFT) strLastExpanded = "";
- // if key with letter pressed
- if( isprint(chrKey) && chrKey!='`') {
- // insert it to editing line
- strEditingLine.InsertChar( iCursorPos, chrKey);
- iCursorPos++;
- // reset history line
- iHistoryLine = 0;
- }
- }
|