// Scorched3D (c) 2000-2003 // // This file is part of Scorched3D. // // Scorched3D is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Scorched3D 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 Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include GameState::GameState(const char *name) : name_(name), fakeMiddleButton_(true), currentMouseState_(0), pendingStimulus_(UINT_MAX), currentState_(UINT_MAX), currentEntry_(0), currentMouseX_(0), currentMouseY_(0), stateLogging_(false), stateTimeLogging_(false) { clearTimers(); } GameState::~GameState() { } void GameState::clear() { stateList_.clear(); } void GameState::setFakeMiddleButton(bool fake) { fakeMiddleButton_ = fake; } void GameState::mouseWheel(short z) { bool skipRest = false; if (currentEntry_) { GameStateEntry *thisEntry = currentEntry_; unsigned thisState = currentState_; StateIList *currentList = ¤tEntry_->subMouseWheelList; if (!currentList->empty()) { StateIList::iterator subItor; for (subItor = currentList->begin(); subItor != currentList->end(); subItor++) { (*subItor)->mouseWheel(thisState, currentMouseX_, currentMouseY_, (int) z, skipRest); if (checkStimulate()) return; if (skipRest) break; } } } } void GameState::mouseMove(int x, int y) { currentMouseX_ = x; currentMouseY_ = y; if (currentEntry_) { GameStateEntry *thisEntry = currentEntry_; unsigned thisState = currentState_; if (MouseButtonMiddle & currentMouseState_) { int diffX = x - mouseMDragX_; mouseMDragX_ = x; int diffY = mouseMDragY_ - y; mouseMDragY_ = y; mouseMoveCall(thisState, MouseButtonMiddle, currentEntry_->subMouseDragMiddleList, x, y, diffX, diffY); } if (fakeMiddleButton_ && (MouseButtonLeft & currentMouseState_ && MouseButtonRight & currentMouseState_)) { int diffX = x - mouseMDragX_; mouseMDragX_ = x; int diffY = mouseMDragY_ - y; mouseMDragY_ = y; mouseMoveCall(thisState, MouseButtonMiddle, currentEntry_->subMouseDragMiddleList, x, y, diffX, diffY); } else { if (MouseButtonLeft & currentMouseState_) { int diffX = x - mouseLDragX_; mouseLDragX_ = x; int diffY = mouseLDragY_ - y; mouseLDragY_ = y; mouseMoveCall(thisState, MouseButtonLeft, currentEntry_->subMouseDragLeftList, x, y, diffX, diffY); } if (MouseButtonRight & currentMouseState_) { int diffX = x - mouseRDragX_; mouseRDragX_ = x; int diffY = mouseRDragY_ - y; mouseRDragY_ = y; mouseMoveCall(thisState, MouseButtonRight, currentEntry_->subMouseDragRightList, x, y, diffX, diffY); } } } } void GameState::mouseMoveCall(const unsigned state, MouseButton button, StateIList ¤tList, int mx, int my, int dx, int dy) { if (!currentList.empty()) { bool skipRest = false; StateIList::iterator subItor; for (subItor = currentList.begin(); subItor != currentList.end(); subItor++) { (*subItor)->mouseDrag(state, button, mx, my, dx, dy, skipRest); if (checkStimulate()) return; if (skipRest) break; } } } void GameState::mouseDown(MouseButton button, int x, int y) { mouseUpDown(button, true, x, y); } void GameState::mouseUp(MouseButton button, int x, int y) { mouseUpDown(button, false, x, y); } void GameState::mouseUpDown(MouseButton button, bool down, int x, int y) { bool skipRest = false; if (currentEntry_) { GameStateEntry *thisEntry = currentEntry_; unsigned thisState = currentState_; StateIList *currentList = 0; if (down) { currentMouseState_ |= (unsigned) button; switch(button) { case MouseButtonRight: mouseRDragX_ = x; mouseRDragY_ = y; currentList = ¤tEntry_->subMouseDownRightList; break; case MouseButtonMiddle: mouseMDragX_ = x; mouseMDragY_ = y; currentList = ¤tEntry_->subMouseDownMiddleList; break; default: mouseLDragX_ = x; mouseLDragY_ = y; currentList = ¤tEntry_->subMouseDownLeftList; break; } } else { currentMouseState_ ^= (unsigned) button; switch(button) { case MouseButtonRight: currentList = ¤tEntry_->subMouseUpRightList; break; case MouseButtonMiddle: currentList = ¤tEntry_->subMouseUpMiddleList; break; default: currentList = ¤tEntry_->subMouseUpLeftList; break; } } if (!currentList->empty()) { StateIList::iterator subItor; for (subItor = currentList->begin(); subItor != currentList->end(); subItor++) { if (down) { (*subItor)->mouseDown(thisState, button, x, y, skipRest); } else { (*subItor)->mouseUp(thisState, button, x, y, skipRest); } if (checkStimulate()) return; if (skipRest) break; } } } } void GameState::simulate(float simTime) { if (checkStimulate()) return; if (currentEntry_) { GameStateEntry *thisEntry = currentEntry_; unsigned thisState = currentState_; timerSimulateTime_ += simTime; if (timerSimulateTime_ > 10.0f) clearTimers(true); timerClock_.getTicksDifference(); int timerCount = 0; std::list::iterator itor; for (itor = thisEntry->loopList.begin(); itor != thisEntry->loopList.end(); itor++) { StateIList::iterator subItor; for (subItor = itor->subLoopList.begin(); subItor != itor->subLoopList.end(); subItor++, timerCount++) { GameStateI *stateI = (*subItor); stateI->simulate(thisState, simTime); if (checkStimulate()) return; timers_[timerCount % 50].simulateTime += timerClock_.getTicksDifference(); timers_[timerCount % 50].gameStateI = stateI; } // Draw after all other elements as the camera // needs to up to date with respect to all other // changes made in the simulate loop itor->current->simulate(thisState, simTime); if (checkStimulate()) return; } if (!thisEntry->subKeyList.empty()) { unsigned int historySize; unsigned int bufferSize; char *buffer = Keyboard::instance()->getkeyboardbuffer(bufferSize); KeyboardHistory::HistoryElement *history = Keyboard::instance()->getkeyboardhistory(historySize); unsigned int keyState = Keyboard::instance()->getKeyboardState(); bool skipRest = false; StateIList::iterator subItor; for (subItor = thisEntry->subKeyList.begin(); subItor != thisEntry->subKeyList.end(); subItor++) { (*subItor)->keyboardCheck(thisState, simTime, buffer, keyState, history, historySize, skipRest); if (checkStimulate()) return; if (skipRest) break; } } if (!thisEntry->condStimList.empty()) { StiulusIList::iterator itor; for (itor = thisEntry->condStimList.begin(); itor != thisEntry->condStimList.end(); itor++) { SimulusIPair &p = *itor; if (p.first->acceptStateChange(thisState, p.second, simTime)) { if (stateLogging_) { Logger::log(formatString("%s::acceptStateChange(%i, %i)", name_.c_str(), thisState, p.second)); } setState(itor->second); return; } if (checkStimulate()) return; } } } } void GameState::draw() { if (currentEntry_) { GameStateEntry *thisEntry = currentEntry_; unsigned thisState = currentState_; timerClock_.getTicksDifference(); int timerCount = 0; std::list::iterator itor; for (itor = thisEntry->loopList.begin(); itor != thisEntry->loopList.end(); itor++) { itor->current->draw(thisState); StateIList::iterator subItor; for (subItor = itor->subLoopList.begin(); subItor != itor->subLoopList.end(); subItor++, timerCount++) { GameStateI *stateI = (*subItor); stateI->draw(thisState); if (checkStimulate()) return; timers_[timerCount % 50].drawTime += timerClock_.getTicksDifference(); timers_[timerCount % 50].gameStateI = stateI; } } } } void GameState::setState(const unsigned state) { if (stateLogging_) { Logger::log(formatString("%s::setState(%i)", name_.c_str(), state)); } clearTimers(); currentState_ = state; currentEntry_ = 0; pendingStimulus_ = UINT_MAX; std::map::iterator itor = stateList_.find(state); if (itor != stateList_.end()) { currentEntry_ = &itor->second; GameStateEntry *thisEntry = currentEntry_; unsigned thisState = currentState_; if (!thisEntry->enterStateList.empty()) { StateIList::iterator subItor; for (subItor = thisEntry->enterStateList.begin(); subItor != thisEntry->enterStateList.end(); subItor++) { GameStateI *s = (*subItor); s->enterState(thisState); } } if (checkStimulate()) return; } else { dialogExit("Scorched3D", formatString( "%s: Failed to find state %i", name_.c_str(), state)); } if (stateLogging_) { Logger::log(formatString("%s::setStateFinished(%i)", name_.c_str(), state)); } } bool GameState::checkStimulate() { if (pendingStimulus_ != UINT_MAX) { std::map::iterator itor = currentEntry_->stimList.find(pendingStimulus_); if (itor != currentEntry_->stimList.end()) { pendingStimulus_ = UINT_MAX; setState(itor->second); return true; } else { dialogExit("Scorched3D", formatString( "%s: Failed to find stimulus %i in state %i", name_.c_str(), pendingStimulus_, currentState_)); } } return false; } void GameState::stimulate(const unsigned stimulus) { if (stateLogging_) { Logger::log(formatString("%s::stimulate(%i)", name_.c_str(), stimulus)); } pendingStimulus_ = stimulus; } GameState::GameStateEntry* GameState::getEntry(const unsigned state) { GameStateEntry *foundEntry = 0; std::map::iterator itor = stateList_.find(state); if (itor == stateList_.end()) { GameStateEntry newEntry; stateList_[state] = newEntry; foundEntry = &stateList_[state]; if (currentState_ == state) { currentEntry_ = &stateList_[state]; } } else { foundEntry = &itor->second; } return foundEntry; } GameState::GameStateSubEntry* GameState::getSubEntry(const unsigned state, GameStateI *entry) { GameStateEntry *foundEntry = getEntry(state); GameStateSubEntry *foundSubEntry = 0; std::list::iterator subItor; for (subItor = foundEntry->loopList.begin(); subItor != foundEntry->loopList.end(); subItor++) { if (subItor->current == entry) { foundSubEntry = &(*subItor); } } if (!foundSubEntry) { GameStateSubEntry newEntry; newEntry.current = entry; foundEntry->loopList.push_back(newEntry); foundSubEntry = &foundEntry->loopList.back(); } return foundSubEntry; } void GameState::addStateLoop(const unsigned state, GameStateI *entry, GameStateI *subEntry) { getSubEntry(state, entry)->subLoopList.push_back(subEntry); } void GameState::addStateEntry(const unsigned state, GameStateI *subEntry) { getEntry(state)->enterStateList.push_back(subEntry); } void GameState::addStateKeyEntry(const unsigned state, GameStateI *subEntry) { getEntry(state)->subKeyList.push_back(subEntry); } void GameState::addStateMouseDownEntry(const unsigned state, const unsigned buttons, GameStateI *subEntry) { if (buttons & MouseButtonLeft) { getEntry(state)->subMouseDownLeftList.push_back(subEntry); } if (buttons & MouseButtonRight) { getEntry(state)->subMouseDownRightList.push_back(subEntry); } if (buttons & MouseButtonMiddle) { getEntry(state)->subMouseDownMiddleList.push_back(subEntry); } } void GameState::addStateMouseUpEntry(const unsigned state, const unsigned buttons, GameStateI *subEntry) { if (buttons & MouseButtonLeft) { getEntry(state)->subMouseUpLeftList.push_back(subEntry); } if (buttons & MouseButtonRight) { getEntry(state)->subMouseUpRightList.push_back(subEntry); } if (buttons & MouseButtonMiddle) { getEntry(state)->subMouseUpMiddleList.push_back(subEntry); } } void GameState::addStateMouseDragEntry(const unsigned state, const unsigned buttons, GameStateI *subEntry) { if (buttons & MouseButtonLeft) { getEntry(state)->subMouseDragLeftList.push_back(subEntry); } if (buttons & MouseButtonRight) { getEntry(state)->subMouseDragRightList.push_back(subEntry); } if (buttons & MouseButtonMiddle) { getEntry(state)->subMouseDragMiddleList.push_back(subEntry); } } void GameState::addStateMouseWheelEntry(const unsigned state, GameStateI *subEntry) { getEntry(state)->subMouseWheelList.push_back(subEntry); } void GameState::addStateStimulus(const unsigned state, const unsigned stim, const unsigned nexts) { GameState::GameStateEntry *entry = getEntry(state); std::map::iterator itor = entry->stimList.find(stim); if (itor == entry->stimList.end()) { entry->stimList[stim] = nexts; } else { DIALOG_ASSERT(0); } } void GameState::addStateStimulus(const unsigned state, GameStateStimulusI *check, const unsigned nexts) { GameState::GameStateEntry *entry = getEntry(state); SimulusIPair pair(check, nexts); entry->condStimList.push_back(pair); } void GameState::clearTimers(bool printTimers) { unsigned int sinceLastTime = overallTimerClock_.getTicksDifference(); if (printTimers && stateTimeLogging_) { unsigned int simulateTotal = 0, drawTotal = 0; for (int i=0; i<50; i++) { if (timers_[i].gameStateI) { simulateTotal += timers_[i].simulateTime; drawTotal += timers_[i].drawTime; } } int bothTotal = drawTotal + simulateTotal; int timeLeft = int(sinceLastTime) - int(bothTotal); if (bothTotal == 0) bothTotal = 1; unsigned int drawTotalPer = (100 * drawTotal) / bothTotal; unsigned int simulateTotalPer = (100 * simulateTotal) / bothTotal; unsigned int timeLeftPer = (100 * timeLeft) / bothTotal; Logger::log(LoggerInfo(LoggerInfo::TypeNormal, "----------------------------------------")); Logger::log(LoggerInfo(LoggerInfo::TypeNormal, formatString("%s Draw : %u (%u), Simulate : %u (%u), Other : %i (%u)", name_.c_str(), drawTotal, drawTotalPer, simulateTotal, simulateTotalPer, timeLeft, timeLeftPer))); for (int i=0; i<50; i++) { if (timers_[i].gameStateI) { unsigned int percentageSimulate = (100 * timers_[i].simulateTime) / bothTotal; unsigned int percentageDraw = (100 * timers_[i].drawTime) / bothTotal; Logger::log(LoggerInfo(LoggerInfo::TypeNormal, formatString("%i:%s - Draw : %u (%u), Simulate : %u (%u)", i, timers_[i].gameStateI->getGameStateIName(), timers_[i].drawTime, percentageDraw, timers_[i].simulateTime, percentageSimulate))); } } } memset(&timers_, 0, sizeof(timers_)); timerSimulateTime_ = 0.0f; }