00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00238 _followerIndex = _arguments[0].intValue;
00239 } else {
00240 _falseBranchIndex = _arguments[0].intValue;
00241 _trueBranchIndex = _arguments[1].intValue;
00242 }
00243 break;
00244 case kFlowEnd:
00245
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
00314 return;
00315 }
00316
00317 Resources::Object *object = reference.resolve<Resources::Object>();
00318 if (!_definitions.contains(object)) {
00319
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
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
00343 for (uint i = 0; i < clean.size(); i++) {
00344 if (!Common::isAlnum(clean[i])) {
00345 clean.setChar(' ', i);
00346 }
00347 }
00348
00349
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 }
00377 }