Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Command.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /*!
  2. * \file src/Command.cpp
  3. * \brief OpenRaider command implementation
  4. *
  5. * \author xythobuz
  6. */
  7. #include <cstdio>
  8. #include <cstring>
  9. #include <assert.h>
  10. #include "WindowSDL.h"
  11. #include "config.h"
  12. #include "Console.h"
  13. #include "Entity.h"
  14. #include "Game.h"
  15. #include "main.h"
  16. #include "math/math.h"
  17. #include "Menu.h"
  18. #include "Sound.h"
  19. #include "TombRaider.h"
  20. #include "utils/strings.h"
  21. #include "utils/time.h"
  22. #include "OpenRaider.h"
  23. int OpenRaider::command(const char *command, std::vector<char *> *args) {
  24. assert(command != NULL);
  25. assert(command[0] != '\0');
  26. assert(args != NULL);
  27. if (strcmp(command, "set") == 0) {
  28. if (args->size() != 2) {
  29. getConsole().print("Invalid use of set-command");
  30. return -1;
  31. } else {
  32. return set(args->at(0), args->at(1));
  33. }
  34. } else if (strcmp(command, "bind") == 0) {
  35. if (args->size() != 2) {
  36. getConsole().print("Invalid use of bind-command");
  37. return -2;
  38. } else {
  39. return bind(args->at(0), args->at(1));
  40. }
  41. } else if (strcmp(command, "quit") == 0) {
  42. exit(0);
  43. } else if (strcmp(command, "load") == 0) {
  44. if (!mRunning) {
  45. getConsole().print("Use load command interactively!");
  46. return -999;
  47. }
  48. char *tmp = bufferString("%s/%s", mPakDir, args->at(0));
  49. int error = getGame().loadLevel(tmp);
  50. delete [] tmp;
  51. return error;
  52. } else if (strcmp(command, "sshot") == 0) {
  53. if (!mRunning) {
  54. getConsole().print("Use sshot command interactively!");
  55. return -999;
  56. }
  57. char *filename = bufferString("%s/sshots/%s", mBaseDir, VERSION);
  58. bool console = (args->size() > 0) && (strcmp(args->at(0), "console") == 0);
  59. bool menu = (args->size() > 0) && (strcmp(args->at(0), "menu") == 0);
  60. if (!console) {
  61. getConsole().setVisible(false);
  62. if (menu)
  63. getMenu().setVisible(true);
  64. frame();
  65. frame(); // Double buffered
  66. }
  67. getRender().screenShot(filename);
  68. if (!console) {
  69. getConsole().setVisible(true);
  70. if (menu)
  71. getMenu().setVisible(false);
  72. }
  73. getConsole().print("Screenshot stored...");
  74. delete filename;
  75. } else if (strcmp(command, "mode") == 0) {
  76. if (args->size() > 0) {
  77. char *mode = args->at(0);
  78. if (strcmp(mode, "wireframe") == 0) {
  79. if (getGame().isLoaded()) {
  80. getRender().setMode(Render::modeWireframe);
  81. getConsole().print("Wireframe mode");
  82. } else {
  83. getConsole().print("Load a level to set this mode!");
  84. return -3;
  85. }
  86. } else if (strcmp(mode, "solid") == 0) {
  87. if (getGame().isLoaded()) {
  88. getRender().setMode(Render::modeSolid);
  89. getConsole().print("Solid mode");
  90. } else {
  91. getConsole().print("Load a level to set this mode!");
  92. return -4;
  93. }
  94. } else if (strcmp(mode, "texture") == 0) {
  95. if (getGame().isLoaded()) {
  96. getRender().setMode(Render::modeTexture);
  97. getConsole().print("Texture mode");
  98. } else {
  99. getConsole().print("Load a level to set this mode!");
  100. return -5;
  101. }
  102. } else if (strcmp(mode, "vertexlight") == 0) {
  103. if (getGame().isLoaded()) {
  104. getRender().setMode(Render::modeVertexLight);
  105. getConsole().print("Vertexlight mode");
  106. } else {
  107. getConsole().print("Load a level to set this mode!");
  108. return -6;
  109. }
  110. } else if (strcmp(mode, "titlescreen") == 0) {
  111. getRender().setMode(Render::modeLoadScreen);
  112. getConsole().print("Titlescreen mode");
  113. } else {
  114. getConsole().print("Invalid use of mode command (%s)!", mode);
  115. return -7;
  116. }
  117. } else {
  118. getConsole().print("Invalid use of mode command!");
  119. return -8;
  120. }
  121. } else if (strcmp(command, "move") == 0) {
  122. if (!mRunning) {
  123. getConsole().print("Use move command interactively!");
  124. return -999;
  125. }
  126. if (args->size() > 0) {
  127. if (getGame().isLoaded()) {
  128. char *move = args->at(0);
  129. if (strcmp(move, "walk") == 0) {
  130. getGame().getLara().setMoveType(Entity::MoveTypeWalk);
  131. getConsole().print("Lara is walking...");
  132. } else if (strcmp(move, "fly") == 0) {
  133. getGame().getLara().setMoveType(Entity::MoveTypeFly);
  134. getConsole().print("Lara is flying...");
  135. } else if (strcmp(move, "noclip") == 0) {
  136. getGame().getLara().setMoveType(Entity::MoveTypeNoClipping);
  137. getConsole().print("Lara is noclipping...");
  138. } else {
  139. getConsole().print("Invalid use of move command (%s)!", move);
  140. return -9;
  141. }
  142. } else {
  143. getConsole().print("Load a level to change the movement type!");
  144. return -10;
  145. }
  146. } else {
  147. getConsole().print("Invalid use of move command!");
  148. return -11;
  149. }
  150. } else if (strcmp(command, "sound") == 0) {
  151. if ((!mRunning) || (!getGame().isLoaded())) {
  152. getConsole().print("Use sound command interactively!");
  153. return -999;
  154. }
  155. if (args->size() > 0) {
  156. getSound().play(atoi(args->at(0)));
  157. } else {
  158. getConsole().print("Invalid use of sound command!");
  159. return -12;
  160. }
  161. } else if (strcmp(command, "animate") == 0) {
  162. if ((!mRunning) || (!getGame().isLoaded())) {
  163. getConsole().print("Use animate command interactively!");
  164. return -999;
  165. }
  166. if (args->size() > 0) {
  167. char c = args->at(0)[0];
  168. if (c == 'n') {
  169. // Step all skeletal models to their next animation
  170. if (getRender().getFlags() & Render::fAnimateAllModels) {
  171. for (unsigned int i = 0; i < getWorld().sizeEntity(); i++) {
  172. Entity &e = getWorld().getEntity(i);
  173. SkeletalModel &m = e.getModel();
  174. if (e.getAnimation() < (m.size() - 1))
  175. e.setAnimation(e.getAnimation() + 1);
  176. else
  177. e.setAnimation(0);
  178. }
  179. } else {
  180. getConsole().print("Animations need to be enabled!");
  181. }
  182. } else if (c == 'p') {
  183. // Step all skeletal models to their previous animation
  184. if (getRender().getFlags() & Render::fAnimateAllModels) {
  185. for (unsigned int i = 0; i < getWorld().sizeEntity(); i++) {
  186. Entity &e = getWorld().getEntity(i);
  187. SkeletalModel &m = e.getModel();
  188. if (e.getAnimation() > 0)
  189. e.setAnimation(e.getAnimation() - 1);
  190. else
  191. if (m.size() > 0)
  192. e.setAnimation(m.size() - 1);
  193. }
  194. } else {
  195. getConsole().print("Animations need to be enabled!");
  196. }
  197. } else {
  198. // Enable or disable animating all skeletal models
  199. bool b;
  200. if (readBool(args->at(0), &b) < 0) {
  201. getConsole().print("Pass BOOL to animate command!");
  202. return -13;
  203. }
  204. if (b)
  205. getRender().setFlags(Render::fAnimateAllModels);
  206. else
  207. getRender().clearFlags(Render::fAnimateAllModels);
  208. getConsole().print(b ? "Animating all models" : "No longer animating all models");
  209. }
  210. } else {
  211. getConsole().print("Invalid use of animate command!");
  212. return -14;
  213. }
  214. } else if (strcmp(command, "light") == 0) {
  215. if (args->size() > 0) {
  216. bool b;
  217. if (readBool(args->at(0), &b) < 0) {
  218. getConsole().print("Pass BOOL to light command!");
  219. return -15;
  220. }
  221. if (b)
  222. getRender().setFlags(Render::fGL_Lights);
  223. else
  224. getRender().clearFlags(Render::fGL_Lights);
  225. getConsole().print("GL-Lights are now %s", b ? "on" : "off");
  226. } else {
  227. getConsole().print("Invalid use of light-command!");
  228. return -16;
  229. }
  230. } else if (strcmp(command, "fog") == 0) {
  231. if (args->size() > 0) {
  232. bool b;
  233. if (readBool(args->at(0), &b) < 0) {
  234. getConsole().print("Pass BOOL to fog command!");
  235. return -17;
  236. }
  237. if (b)
  238. getRender().setFlags(Render::fFog);
  239. else
  240. getRender().clearFlags(Render::fFog);
  241. getConsole().print("Fog is now %s", b ? "on" : "off");
  242. } else {
  243. getConsole().print("Invalid use of fog-command!");
  244. return -18;
  245. }
  246. } else if (strcmp(command, "viewmodel") == 0) {
  247. if ((!mRunning) || (!getGame().isLoaded())) {
  248. getConsole().print("Use viewmodel command interactively!");
  249. return -999;
  250. }
  251. unsigned int n = atoi(args->at(0));
  252. if (n < getWorld().sizeSkeletalModel())
  253. getGame().getLara().setSkeletalModel(n);
  254. else {
  255. getConsole().print("Invalid SkeletalModel index!");
  256. return -66;
  257. }
  258. } else if (strcmp(command, "pos") == 0) {
  259. if ((!mRunning) || (!getGame().isLoaded())) {
  260. getConsole().print("Use pos command interactively!");
  261. return -21;
  262. }
  263. getGame().getLara().print();
  264. } else if (strcmp(command, "vmodel") == 0) {
  265. if (args->size() > 0) {
  266. bool b;
  267. if (readBool(args->at(0), &b) < 0) {
  268. getConsole().print("Pass BOOL to vmodel command!");
  269. return -22;
  270. }
  271. if (b)
  272. getRender().setFlags(Render::fViewModel);
  273. else
  274. getRender().clearFlags(Render::fViewModel);
  275. getConsole().print("Viewmodel is now %s", b ? "on" : "off");
  276. } else {
  277. getConsole().print("Invalid use of vmodel-command!");
  278. return -23;
  279. }
  280. } else if (strcmp(command, "ralpha") == 0) {
  281. if (args->size() > 0) {
  282. bool b;
  283. if (readBool(args->at(0), &b) < 0) {
  284. getConsole().print("Pass BOOL to ralpha command!");
  285. return -24;
  286. }
  287. if (b)
  288. getRender().setFlags(Render::fRoomAlpha);
  289. else
  290. getRender().clearFlags(Render::fRoomAlpha);
  291. getConsole().print("Room Alpha is now %s", b ? "on" : "off");
  292. } else {
  293. getConsole().print("Invalid use of ralpha-command!");
  294. return -25;
  295. }
  296. } else if (strcmp(command, "vis") == 0) {
  297. if (args->size() > 0) {
  298. bool b;
  299. if (readBool(args->at(0), &b) < 0) {
  300. getConsole().print("Pass BOOL to vis command!");
  301. return -28;
  302. }
  303. if (b)
  304. getRender().setFlags(Render::fUsePortals);
  305. else
  306. getRender().clearFlags(Render::fUsePortals);
  307. getConsole().print("Portals are now %s", b ? "on" : "off");
  308. } else {
  309. getConsole().print("Invalid use of vis-command!");
  310. return -29;
  311. }
  312. } else if (strcmp(command, "upf") == 0) {
  313. if (args->size() > 0) {
  314. bool b;
  315. if (readBool(args->at(0), &b) < 0) {
  316. getConsole().print("Pass BOOL to upf command!");
  317. return -30;
  318. }
  319. if (b)
  320. getRender().setFlags(Render::fUpdateRoomListPerFrame);
  321. else
  322. getRender().clearFlags(Render::fUpdateRoomListPerFrame);
  323. getConsole().print("URLPF is now %s", b ? "on" : "off");
  324. } else {
  325. getConsole().print("Invalid use of upf-command!");
  326. return -31;
  327. }
  328. } else if (strcmp(command, "entmodel") == 0) {
  329. if (args->size() > 0) {
  330. bool b;
  331. if (readBool(args->at(0), &b) < 0) {
  332. getConsole().print("Pass BOOL to entmodel command!");
  333. return -38;
  334. }
  335. if (b)
  336. getRender().setFlags(Render::fEntityModels);
  337. else
  338. getRender().clearFlags(Render::fEntityModels);
  339. getConsole().print("Entmodels are now %s", b ? "on" : "off");
  340. } else {
  341. getConsole().print("Invalid use of entmodel-command!");
  342. return -39;
  343. }
  344. } else if (strcmp(command, "oneroom") == 0) {
  345. if (args->size() > 0) {
  346. bool b;
  347. if (readBool(args->at(0), &b) < 0) {
  348. getConsole().print("Pass BOOL to oneroom command!");
  349. return -40;
  350. }
  351. if (b)
  352. getRender().setFlags(Render::fOneRoom);
  353. else
  354. getRender().clearFlags(Render::fOneRoom);
  355. getConsole().print("Rendering one room is now %s", b ? "on" : "off");
  356. } else {
  357. getConsole().print("Invalid use of oneroom-command!");
  358. return -41;
  359. }
  360. } else if (strcmp(command, "allrooms") == 0) {
  361. if (args->size() > 0) {
  362. bool b;
  363. if (readBool(args->at(0), &b) < 0) {
  364. getConsole().print("Pass BOOL to allrooms command!");
  365. return -42;
  366. }
  367. if (b)
  368. getRender().setFlags(Render::fAllRooms);
  369. else
  370. getRender().clearFlags(Render::fAllRooms);
  371. getConsole().print("Rendering all rooms is now %s", b ? "on" : "off");
  372. } else {
  373. getConsole().print("Invalid use of allrooms-command!");
  374. return -43;
  375. }
  376. } else if (strcmp(command, "ponytail") == 0) {
  377. if (args->size() > 0) {
  378. bool b;
  379. if (readBool(args->at(0), &b) < 0) {
  380. getConsole().print("Pass BOOL to ponytail command!");
  381. return -44;
  382. }
  383. if (b)
  384. getRender().setFlags(Render::fRenderPonytail);
  385. else
  386. getRender().clearFlags(Render::fRenderPonytail);
  387. getConsole().print("Ponytail is now %s", b ? "on" : "off");
  388. } else {
  389. getConsole().print("Invalid use of ponytail-command!");
  390. return -45;
  391. }
  392. } else if (strcmp(command, "pigtail") == 0) {
  393. if ((!mRunning) || (!getGame().isLoaded())) {
  394. getConsole().print("Use pigtail command interactively!");
  395. return -999;
  396. }
  397. if (args->size() > 0) {
  398. bool b;
  399. if (readBool(args->at(0), &b) < 0) {
  400. getConsole().print("Pass BOOL to pigtail command!");
  401. return -46;
  402. }
  403. SkeletalModel &tmp = getGame().getLara().getModel();
  404. tmp.setPigTail(b);
  405. getConsole().print("Pigtail is now %s", b ? "on" : "off");
  406. } else {
  407. getConsole().print("Invalid use of pigtail-command!");
  408. return -47;
  409. }
  410. } else if (strcmp(command, "ponypos") == 0) {
  411. if ((!mRunning) || (!getGame().isLoaded())) {
  412. getConsole().print("Use ponypos command interactively!");
  413. return -999;
  414. }
  415. if (args->size() > 3) {
  416. SkeletalModel &tmp = getGame().getLara().getModel();
  417. tmp.setPonyPos((float)atof(args->at(0)), (float)atof(args->at(1)),
  418. (float)atof(args->at(2)), (float)atof(args->at(3)));
  419. } else {
  420. getConsole().print("Invalid use of ponypos-command!");
  421. return -48;
  422. }
  423. } else if (strcmp(command, "help") == 0) {
  424. if (args->size() == 0) {
  425. getConsole().print("Available commands:");
  426. getConsole().print(" load - load a level");
  427. getConsole().print(" set - set a parameter");
  428. getConsole().print(" bind - bind a keyboard/mouse action");
  429. getConsole().print(" sshot - make a screenshot");
  430. getConsole().print(" move - [walk|fly|noclip]");
  431. getConsole().print(" sound - INT - Test play sound");
  432. getConsole().print(" mode - MODE - Render mode");
  433. getConsole().print(" animate - [BOOL|n|p] - Animate models");
  434. getConsole().print(" light - BOOL - GL Lights");
  435. getConsole().print(" fog - BOOL - GL Fog");
  436. getConsole().print(" viewmodel - INT - Change Laras model");
  437. getConsole().print(" pos - Print position info");
  438. getConsole().print(" vmodel - BOOL - View Model");
  439. getConsole().print(" ralpha - BOOL - Room Alpha");
  440. getConsole().print(" vis - BOOL - Use Portals");
  441. getConsole().print(" upf - BOOL - Update Room List Per Frame");
  442. getConsole().print(" entmodel - BOOL");
  443. getConsole().print(" oneroom - BOOL");
  444. getConsole().print(" allrooms - BOOL");
  445. getConsole().print(" ponytail - BOOL");
  446. getConsole().print(" pigtail - BOOL");
  447. getConsole().print(" ponypos - FLOAT FLOAT FLOAT FLOAT - x y z angle");
  448. getConsole().print(" help - print command help");
  449. getConsole().print(" quit - exit OpenRaider");
  450. getConsole().print("Use help COMMAND to get additional info");
  451. } else if (args->size() == 1) {
  452. return help(args->at(0));
  453. } else {
  454. getConsole().print("Invalid use of help-command");
  455. return -49;
  456. }
  457. } else {
  458. getConsole().print("Unknown command: %s ", command);
  459. return -50;
  460. }
  461. return 0;
  462. }
  463. int OpenRaider::help(const char *cmd) {
  464. assert(cmd != NULL);
  465. assert(cmd[0] != '\0');
  466. if (strcmp(cmd, "set") == 0) {
  467. getConsole().print("set-Command Usage:");
  468. getConsole().print(" set VAR VAL");
  469. getConsole().print("Available Variables:");
  470. getConsole().print(" basedir STRING");
  471. getConsole().print(" pakdir STRING");
  472. getConsole().print(" audiodir STRING");
  473. getConsole().print(" datadir STRING");
  474. getConsole().print(" font STRING");
  475. getConsole().print(" gldriver STRING");
  476. getConsole().print(" size \"INTxINT\"");
  477. getConsole().print(" fullscreen BOOL");
  478. getConsole().print(" audio BOOL");
  479. getConsole().print(" volume BOOL");
  480. getConsole().print(" mouse_x FLOAT");
  481. getConsole().print(" mouse_y FLOAT");
  482. getConsole().print(" fps BOOL");
  483. getConsole().print("Enclose STRINGs with \"\"!");
  484. getConsole().print("size expects a STRING in the specified format");
  485. } else if (strcmp(cmd, "bind") == 0) {
  486. getConsole().print("bind-Command Usage:");
  487. getConsole().print(" bind ACTION KEY");
  488. getConsole().print("Available Actions:");
  489. getConsole().print(" menu");
  490. getConsole().print(" console");
  491. getConsole().print(" forward");
  492. getConsole().print(" backward");
  493. getConsole().print(" left");
  494. getConsole().print(" right");
  495. getConsole().print(" jump");
  496. getConsole().print(" crouch");
  497. getConsole().print(" use");
  498. getConsole().print(" holster");
  499. getConsole().print("Key-Format:");
  500. getConsole().print(" 'a' or '1' for character/number keys");
  501. getConsole().print(" \"leftctrl\" for symbols and special keys");
  502. } else if (strcmp(cmd, "load") == 0) {
  503. getConsole().print("load-Command Usage:");
  504. getConsole().print(" load levelfile.name");
  505. } else if (strcmp(cmd, "game") == 0) {
  506. getConsole().print("Use \"game help\" for more info");
  507. } else if (strcmp(cmd, "sshot") == 0) {
  508. getConsole().print("sshot-Command Usage:");
  509. getConsole().print(" sshot [console|menu]");
  510. getConsole().print("Add console/menu to capture them too");
  511. } else if (strcmp(cmd, "sound") == 0) {
  512. getConsole().print("sound-Command Usage:");
  513. getConsole().print(" sound INT");
  514. getConsole().print("Where INT is a valid sound ID integer");
  515. } else if (strcmp(cmd, "move") == 0) {
  516. getConsole().print("move-Command Usage:");
  517. getConsole().print(" move COMMAND");
  518. getConsole().print("Where COMMAND is one of the following:");
  519. getConsole().print(" walk");
  520. getConsole().print(" fly");
  521. getConsole().print(" noclip");
  522. } else if (strcmp(cmd, "mode") == 0) {
  523. getConsole().print("mode-Command Usage:");
  524. getConsole().print(" mode MODE");
  525. getConsole().print("Where MODE is one of the following:");
  526. getConsole().print(" wireframe");
  527. getConsole().print(" solid");
  528. getConsole().print(" texture");
  529. getConsole().print(" vertexlight");
  530. getConsole().print(" titlescreen");
  531. } else if (strcmp(cmd, "animate") == 0) {
  532. getConsole().print("animate-Command Usage:");
  533. getConsole().print(" animate [n|p|BOOL]");
  534. getConsole().print("Where the commands have the following meaning:");
  535. getConsole().print(" BOOL to (de)activate animating all models");
  536. getConsole().print(" n to step all models to their next animation");
  537. getConsole().print(" p to step all models to their previous animation");
  538. } else {
  539. getConsole().print("No help available for %s", cmd);
  540. return -1;
  541. }
  542. return 0;
  543. }