ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

tools/command.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/tools/command.h"
00024 
00025 #include "common/debug.h"
00026 #include "common/tokenizer.h"
00027 
00028 namespace Stark {
00029 namespace Tools {
00030 
00031 Command::Command(Command *command) {
00032     _index = command->_index;
00033     _subType = command->_subType;
00034     _subTypeDesc = command->_subTypeDesc;
00035     _arguments = command->_arguments;
00036 }
00037 
00038 Command::Command(Resources::Command *resource) {
00039     _index = resource->getIndex();
00040     _subType = (Resources::Command::SubType) resource->getSubType();
00041     _subTypeDesc = searchSubTypeDesc(_subType);
00042     _arguments = resource->getArguments();
00043 }
00044 
00045 const Command::SubTypeDesc *Command::searchSubTypeDesc(Resources::Command::SubType subType) {
00046     static const SubTypeDesc typeNames[] = {
00047             { Resources::Command::kCommandBegin,               "begin",                      kFlowNormal },
00048             { Resources::Command::kCommandEnd,                 "end",                        kFlowEnd    },
00049             { Resources::Command::kScriptCall,                 "scriptCall",                 kFlowNormal },
00050             { Resources::Command::kDialogCall,                 "dialogCall",                 kFlowNormal },
00051             { Resources::Command::kSetInteractiveMode,         "setInteractiveMode",         kFlowNormal },
00052             { Resources::Command::kLocationGoTo,               "locationGoTo",               kFlowEnd    },
00053             { Resources::Command::kWalkTo,                     "walkTo",                     kFlowBranch },
00054             { Resources::Command::kGameLoop,                   "gameLoop",                   kFlowNormal },
00055             { Resources::Command::kScriptPause,                "scriptPause",                kFlowNormal },
00056             { Resources::Command::kScriptPauseRandom,          "scriptPauseRandom",          kFlowNormal },
00057             { Resources::Command::kScriptPauseSkippable,       "scriptPauseSkippable",       kFlowNormal },
00058             { Resources::Command::kScriptAbort,                "scriptAbort",                kFlowNormal },
00059             { Resources::Command::kExit2DLocation,             "exit2DLocation",             kFlowEnd    },
00060             { Resources::Command::kGoto2DLocation,             "goto2DLocation",             kFlowEnd    },
00061             { Resources::Command::kRumbleScene,                "rumbleScene",                kFlowNormal },
00062             { Resources::Command::kFadeScene,                  "fadeScene",                  kFlowNormal },
00063             { Resources::Command::kSwayScene,                  "swayScene",                  kFlowNormal },
00064             { Resources::Command::kLocationGoToNewCD,          "locationGoToNewCD",          kFlowEnd    },
00065             { Resources::Command::kGameEnd,                    "gameEnd",                    kFlowNormal },
00066             { Resources::Command::kInventoryOpen,              "inventoryOpen",              kFlowNormal },
00067             { Resources::Command::kFloatScene,                 "floatScene",                 kFlowNormal },
00068             { Resources::Command::kBookOfSecretsOpen,          "bookOfSecretsOpen",          kFlowNormal },
00069             { Resources::Command::kDoNothing,                  "doNothing",                  kFlowNormal },
00070             { Resources::Command::kItem3DPlaceOn,              "item3DPlaceOn",              kFlowNormal },
00071             { Resources::Command::kItem3DWalkTo,               "item3DWalkTo",               kFlowNormal },
00072             { Resources::Command::kItem3DFollowPath,           "item3DFollowPath",           kFlowNormal },
00073             { Resources::Command::kItemLookAt,                 "itemLookAt",                 kFlowNormal },
00074             { Resources::Command::kItem2DFollowPath,           "item2DFollowPath",           kFlowNormal },
00075             { Resources::Command::kItemEnable,                 "itemEnable",                 kFlowNormal },
00076             { Resources::Command::kItemSetActivity,            "itemSetActivity",            kFlowNormal },
00077             { Resources::Command::kItemSelectInInventory,      "itemSelectInInventory",      kFlowNormal },
00078             { Resources::Command::kUseAnimHierarchy,           "useAnimHierarchy",           kFlowNormal },
00079             { Resources::Command::kPlayAnimation,              "playAnimation",              kFlowNormal },
00080             { Resources::Command::kScriptEnable,               "scriptEnable",               kFlowNormal },
00081             { Resources::Command::kShowPlay,                   "showPlay",                   kFlowNormal },
00082             { Resources::Command::kKnowledgeSetBoolean,        "knowledgeSetBoolean",        kFlowNormal },
00083             { Resources::Command::kKnowledgeSetInteger,        "knowledgeSetInteger",        kFlowNormal },
00084             { Resources::Command::kKnowledgeAddInteger,        "knowledgeAddInteger",        kFlowNormal },
00085             { Resources::Command::kEnableFloorField,           "enableFloorField",           kFlowNormal },
00086             { Resources::Command::kPlayAnimScriptItem,         "playAnimScriptItem",         kFlowNormal },
00087             { Resources::Command::kItemAnimFollowPath,         "itemAnimFollowPath",         kFlowNormal },
00088             { Resources::Command::kKnowledgeAssignBool,        "knowledgeAssignBool",        kFlowNormal },
00089             { Resources::Command::kKnowledgeAssignInteger,     "knowledgeAssignInteger",     kFlowNormal },
00090             { Resources::Command::kLocationScrollTo,           "locationScrollTo",           kFlowNormal },
00091             { Resources::Command::kSoundPlay,                  "soundPlay",                  kFlowNormal },
00092             { Resources::Command::kKnowledgeSetIntRandom,      "knowledgeSetIntRandom",      kFlowNormal },
00093             { Resources::Command::kKnowledgeSubValue,          "knowledgeSubValue",          kFlowNormal },
00094             { Resources::Command::kItemLookDirection,          "itemLookDirection",          kFlowNormal },
00095             { Resources::Command::kStopPlayingSound,           "stopPlayingSound",           kFlowNormal },
00096             { Resources::Command::kLayerGoTo,                  "layerGoTo",                  kFlowNormal },
00097             { Resources::Command::kLayerEnable,                "layerEnable",                kFlowNormal },
00098             { Resources::Command::kLocationScrollSet,          "locationScrollSet",          kFlowNormal },
00099             { Resources::Command::kFullMotionVideoPlay,        "fullMotionVideoPlay",        kFlowNormal },
00100             { Resources::Command::kAnimSetFrame,               "animSetFrame",               kFlowNormal },
00101             { Resources::Command::kKnowledgeAssignNegatedBool, "knowledgeAssignNegatedBool", kFlowNormal },
00102             { Resources::Command::kDiaryEnableEntry,           "diaryEnableEntry",           kFlowNormal },
00103             { Resources::Command::kPATChangeTooltip,           "pATChangeTooltip",           kFlowNormal },
00104             { Resources::Command::kSoundChange,                "soundChange",                kFlowNormal },
00105             { Resources::Command::kLightSetColor,              "lightSetColor",              kFlowNormal },
00106             { Resources::Command::kLightFollowPath,            "lightFollowPath",            kFlowNormal },
00107             { Resources::Command::kItem3DRunTo,                "item3DRunTo",                kFlowNormal },
00108             { Resources::Command::kItemPlaceDirection,         "itemPlaceDirection",         kFlowNormal },
00109             { Resources::Command::kItemRotateDirection,        "itemRotateDirection",        kFlowNormal },
00110             { Resources::Command::kActivateTexture,            "activateTexture",            kFlowNormal },
00111             { Resources::Command::kActivateMesh,               "activateMesh",               kFlowNormal },
00112             { Resources::Command::kItem3DSetWalkTarget,        "item3DSetWalkTarget",        kFlowNormal },
00113             { Resources::Command::kSpeakWithoutTalking,        "speakWithoutTalking",        kFlowNormal },
00114             { Resources::Command::kIsOnFloorField,             "isOnFloorField",             kFlowBranch },
00115             { Resources::Command::kIsItemEnabled,              "isItemEnabled",              kFlowBranch },
00116             { Resources::Command::kIsScriptEnabled,            "isScriptEnabled",            kFlowBranch },
00117             { Resources::Command::kIsKnowledgeBooleanSet,      "isKnowledgeBooleanSet",      kFlowBranch },
00118             { Resources::Command::kIsKnowledgeIntegerInRange,  "isKnowledgeIntegerInRange",  kFlowBranch },
00119             { Resources::Command::kIsKnowledgeIntegerAbove,    "isKnowledgeIntegerAbove",    kFlowBranch },
00120             { Resources::Command::kIsKnowledgeIntegerEqual,    "isKnowledgeIntegerEqual",    kFlowBranch },
00121             { Resources::Command::kIsKnowledgeIntegerLower,    "isKnowledgeIntegerLower",    kFlowBranch },
00122             { Resources::Command::kIsScriptActive,             "isScriptActive",             kFlowBranch },
00123             { Resources::Command::kIsRandom,                   "isRandom",                   kFlowBranch },
00124             { Resources::Command::kIsAnimScriptItemReached,    "isAnimScriptItemReached",    kFlowBranch },
00125             { Resources::Command::kIsItemOnPlace,              "isItemOnPlace",              kFlowBranch },
00126             { Resources::Command::kIsAnimPlaying,              "isAnimPlaying",              kFlowBranch },
00127             { Resources::Command::kIsItemActivity,             "isItemActivity",             kFlowBranch },
00128             { Resources::Command::kIsItemNearPlace,            "isItemNearPlace",            kFlowBranch },
00129             { Resources::Command::kIsAnimAtTime,               "isAnimAtTime",               kFlowBranch },
00130             { Resources::Command::kIsLocation2D,               "isLocation2D",               kFlowBranch },
00131             { Resources::Command::kIsInventoryOpen,            "isInventoryOpen",            kFlowBranch }
00132     };
00133 
00134     for (uint i = 0; i < ARRAYSIZE(typeNames); i++) {
00135         if (typeNames[i].subType == subType) {
00136             return &typeNames[i];
00137         }
00138     }
00139 
00140     return nullptr;
00141 }
00142 
00143 Command::ArgumentArray Command::getEffectiveArguments() const {
00144     uint effectiveArgumentsStart;
00145     switch (_subTypeDesc->controlFlowType) {
00146         case kFlowEnd:
00147             effectiveArgumentsStart = 0;
00148             break;
00149         case kFlowNormal:
00150             effectiveArgumentsStart = 1;
00151             break;
00152         case kFlowBranch:
00153             effectiveArgumentsStart = 2;
00154             break;
00155         default:
00156             error("Unhandled control flow type '%d'", _subTypeDesc->controlFlowType);
00157     }
00158 
00159     ArgumentArray effectiveArguments;
00160     for (uint i = effectiveArgumentsStart; i < _arguments.size(); i++) {
00161         effectiveArguments.push_back(_arguments[i]);
00162     }
00163 
00164     return  effectiveArguments;
00165 }
00166 
00167 Common::String Command::describeArguments(DefinitionRegistry *definitions) const {
00168     Common::String desc;
00169 
00170     for (uint i = 0; i < _arguments.size(); i++) {
00171         switch (_arguments[i].type) {
00172             case Resources::Command::Argument::kTypeInteger1:
00173             case Resources::Command::Argument::kTypeInteger2:
00174                 desc += Common::String::format("%d", _arguments[i].intValue);
00175                 break;
00176 
00177             case Resources::Command::Argument::kTypeResourceReference: {
00178                 if (definitions) {
00179                     desc += definitions->getFromReference(_arguments[i].referenceValue);
00180                 } else {
00181                     desc += _arguments[i].referenceValue.describe();
00182                 }
00183             }
00184                 break;
00185             case Resources::Command::Argument::kTypeString:
00186                 desc += _arguments[i].stringValue;
00187                 break;
00188             default:
00189                 error("Unknown argument type %d", _arguments[i].type);
00190         }
00191 
00192         if (i != _arguments.size() - 1) {
00193             desc += ", ";
00194         }
00195     }
00196 
00197     return desc;
00198 }
00199 
00200 void Command::printCall() const {
00201     debug("%d: %s(%s)", _index, _subTypeDesc->name, describeArguments(nullptr).c_str());
00202 }
00203 
00204 uint16 Command::getIndex() const {
00205     return _index;
00206 }
00207 
00208 bool Command::hasSubtypeDescription() const {
00209     return _subTypeDesc != nullptr;
00210 }
00211 
00212 Resources::Command::SubType Command::getSubType() const {
00213     return _subType;
00214 }
00215 
00216 CFGCommand::CFGCommand(Resources::Command *resource) :
00217         Command(resource),
00218         _followerIndex(-1),
00219         _trueBranchIndex(-1),
00220         _falseBranchIndex(-1),
00221         _follower(nullptr),
00222         _trueBranch(nullptr),
00223         _falseBranch(nullptr),
00224         _block(nullptr) {
00225     if (_subTypeDesc) {
00226         initBranches();
00227     }
00228 }
00229 
00230 void CFGCommand::initBranches() {
00231     switch (_subTypeDesc->controlFlowType) {
00232         case kFlowNormal:
00233             _followerIndex = _arguments[0].intValue;
00234             break;
00235         case kFlowBranch:
00236             if (_arguments[0].intValue == _arguments[1].intValue) {
00237                 // Degenerate conditions are handled here so that blocks are not split after them
00238                 _followerIndex = _arguments[0].intValue;
00239             } else {
00240                 _falseBranchIndex = _arguments[0].intValue;
00241                 _trueBranchIndex = _arguments[1].intValue;
00242             }
00243             break;
00244         case kFlowEnd:
00245             // No followers
00246             break;
00247     }
00248 }
00249 
00250 bool CFGCommand::isEntryPoint() const {
00251     return _subType == Resources::Command::kCommandBegin;
00252 }
00253 
00254 bool CFGCommand::isBranch() const {
00255     return _trueBranchIndex >= 0 && _falseBranchIndex >= 0;
00256 }
00257 
00258 bool CFGCommand::isBranchTarget() const {
00259     return _predecessors.size() > 1;
00260 }
00261 
00262 Block *CFGCommand::getBlock() const {
00263     return _block;
00264 }
00265 
00266 void CFGCommand::setBlock(Block *block) {
00267     _block = block;
00268 }
00269 
00270 CFGCommand *CFGCommand::getFollower() const {
00271     return _follower;
00272 }
00273 
00274 CFGCommand *CFGCommand::getTrueBranch() const {
00275     return _trueBranch;
00276 }
00277 
00278 CFGCommand *CFGCommand::getFalseBranch() const {
00279     return _falseBranch;
00280 }
00281 
00282 void CFGCommand::linkBranches(const Common::Array<CFGCommand *> &commands) {
00283     if (_followerIndex >= 0) {
00284         _follower = findCommandWithIndex(commands, _followerIndex);
00285         _follower->_predecessors.push_back(this);
00286     }
00287 
00288     if (_falseBranchIndex >= 0) {
00289         _falseBranch = findCommandWithIndex(commands, _falseBranchIndex);
00290         _falseBranch->_predecessors.push_back(this);
00291     }
00292 
00293     if (_trueBranchIndex >= 0) {
00294         _trueBranch = findCommandWithIndex(commands, _trueBranchIndex);
00295         _trueBranch->_predecessors.push_back(this);
00296     }
00297 }
00298 
00299 CFGCommand *CFGCommand::findCommandWithIndex(const Common::Array<CFGCommand *> &commands, int32 index) {
00300     for (uint i = 0; i < commands.size(); i++) {
00301         CFGCommand *command = commands[i];
00302 
00303         if (command->_index == index) {
00304             return command;
00305         }
00306     }
00307 
00308     error("Unable to find command with index %d", index);
00309 }
00310 
00311 void DefinitionRegistry::registerReference(const ResourceReference &reference) {
00312     if (!reference.canResolve()) {
00313         // The reference uses archives that are not currently loaded
00314         return;
00315     }
00316 
00317     Resources::Object *object = reference.resolve<Resources::Object>();
00318     if (!_definitions.contains(object)) {
00319         // TODO: There is no guarantee the definition is unique
00320         _definitions[object] = object->getType().getName() + stringToCamelCase(object->getName());;
00321     }
00322 }
00323 
00324 Common::String DefinitionRegistry::getFromReference(const ResourceReference &reference) const {
00325     if (!reference.canResolve()) {
00326         // The reference uses archives that are not currently loaded
00327         return reference.describe();
00328     }
00329 
00330     Resources::Object *object = reference.resolve<Resources::Object>();
00331 
00332     if (_definitions.contains(object)) {
00333         return _definitions.getVal(object);
00334     } else {
00335         return reference.describe();
00336     }
00337 }
00338 
00339 Common::String DefinitionRegistry::stringToCamelCase(const Common::String &input) {
00340     Common::String clean = input;
00341 
00342     // First replace all non alphanumerical characters with spaces
00343     for (uint i = 0; i < clean.size(); i++) {
00344         if (!Common::isAlnum(clean[i])) {
00345             clean.setChar(' ', i);
00346         }
00347     }
00348 
00349     // Then turn the string into camel case
00350     Common::String output;
00351     Common::StringTokenizer tokens = Common::StringTokenizer(clean);
00352     while (!tokens.empty()) {
00353         Common::String token = tokens.nextToken();
00354 
00355         char upperFirstLetter = toupper(token[0]);
00356         token.setChar(upperFirstLetter, 0);
00357 
00358         output += token;
00359     }
00360 
00361     return output;
00362 }
00363 
00364 void DefinitionRegistry::printAll() const {
00365     DefinitionMap::const_iterator it = _definitions.begin();
00366     while (it != _definitions.end()) {
00367         ResourceReference reference;
00368         reference.buildFromResource(it->_key);
00369 
00370         debug("let %s = %s", it->_value.c_str(), reference.describe().c_str());
00371 
00372         it++;
00373     }
00374 }
00375 
00376 } // End of namespace Tools
00377 } // End of namespace Stark


Generated on Sat Feb 23 2019 05:00:59 for ResidualVM by doxygen 1.7.1
curved edge   curved edge