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.

Game.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*!
  2. * \file src/Game.cpp
  3. * \brief Game abstraction
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include <map>
  9. #include <cstdlib>
  10. #include "global.h"
  11. #include "Console.h"
  12. #include "Game.h"
  13. #include "OpenRaider.h"
  14. #include "Sound.h"
  15. #include "StaticMesh.h"
  16. #include "utils/strings.h"
  17. #include "games/TombRaider1.h"
  18. #ifdef MULTITEXTURE
  19. std::map<int, int> gMapTex2Bump;
  20. #endif
  21. Game::Game() {
  22. mLoaded = false;
  23. mName = NULL;
  24. mLara = -1;
  25. mTextureStart = 0;
  26. mTextureOffset = 0;
  27. }
  28. Game::~Game() {
  29. destroy();
  30. }
  31. unsigned int Game::getTextureStart() {
  32. return mTextureStart;
  33. }
  34. unsigned int Game::getTextureOffset() {
  35. return mTextureOffset;
  36. }
  37. int Game::initialize() {
  38. // Enable Renderer
  39. mTextureStart = getRender().initTextures(getOpenRaider().mDataDir);
  40. getRender().setMode(Render::modeLoadScreen);
  41. return 0;
  42. }
  43. void Game::destroy() {
  44. delete [] mName;
  45. mName = NULL;
  46. mLoaded = false;
  47. mLara = -1;
  48. getRender().setMode(Render::modeDisabled);
  49. getWorld().destroy();
  50. getRender().ClearWorld();
  51. getSound().clear(); // Remove all previously loaded sounds
  52. }
  53. bool Game::isLoaded() {
  54. return mLoaded;
  55. }
  56. int Game::loadLevel(const char *level) {
  57. if (mLoaded)
  58. destroy();
  59. mName = bufferString("%s", level);
  60. getConsole().print("Loading %s", mName);
  61. int error = mTombRaider.Load(mName);
  62. if (error != 0)
  63. return error;
  64. // If required, load the external sound effect file MAIN.SFX into TombRaider
  65. if ((mTombRaider.getEngine() == TR_VERSION_2) || (mTombRaider.getEngine() == TR_VERSION_3)) {
  66. char *tmp = bufferString("%sMAIN.SFX", level); // Ensure theres enough space
  67. size_t length = strlen(tmp);
  68. size_t dir = 0;
  69. for (int i = length - 1; i >= 0; i--) {
  70. if ((tmp[i] == '/') || (tmp[i] == '\\')) {
  71. dir = i + 1; // Find where the filename (bla.tr2) starts
  72. break;
  73. }
  74. }
  75. strcpy(tmp + dir, "MAIN.SFX"); // overwrite the name itself with MAIN.SFX
  76. tmp[dir + 8] = '\0';
  77. error = mTombRaider.loadSFX(tmp);
  78. if (error != 0)
  79. getConsole().print("Could not load %s", tmp);
  80. delete [] tmp;
  81. }
  82. // Process data
  83. processTextures();
  84. processRooms();
  85. processModels();
  86. processSprites();
  87. processMoveables();
  88. processPakSounds();
  89. mTombRaider.reset();
  90. if (mLara == -1) {
  91. getConsole().print("Can't find Lara entity in level pak!");
  92. destroy();
  93. return -1;
  94. } else {
  95. mLoaded = true;
  96. getRender().setMode(Render::modeVertexLight);
  97. return 0;
  98. }
  99. }
  100. void Game::handleAction(ActionEvents action, bool isFinished) {
  101. if (mLoaded && (!isFinished)) {
  102. if (action == forwardAction) {
  103. getLara().move('f');
  104. } else if (action == backwardAction) {
  105. getLara().move('b');
  106. } else if (action == leftAction) {
  107. getLara().move('l');
  108. } else if (action == rightAction) {
  109. getLara().move('r');
  110. } else if (action == jumpAction) {
  111. } else if (action == crouchAction) {
  112. } else if (action == useAction) {
  113. } else if (action == holsterAction) {
  114. } else if (action == walkAction) {
  115. }
  116. }
  117. }
  118. void Game::handleMouseMotion(int xrel, int yrel) {
  119. if (mLoaded) {
  120. // Move Camera on X Axis
  121. if (xrel > 0)
  122. while (xrel-- > 0)
  123. getCamera().command(CAMERA_ROTATE_RIGHT);
  124. else if (xrel < 0)
  125. while (xrel++ < 0)
  126. getCamera().command(CAMERA_ROTATE_LEFT);
  127. // Move Camera on Y Axis
  128. if (yrel > 0)
  129. while (yrel-- > 0)
  130. getCamera().command(CAMERA_ROTATE_UP);
  131. else if (yrel < 0)
  132. while (yrel++ < 0)
  133. getCamera().command(CAMERA_ROTATE_DOWN);
  134. // Fix Laras rotation
  135. getLara().setAngle(getCamera().getRadianYaw());
  136. }
  137. }
  138. Entity &Game::getLara() {
  139. assert(mLara >= 0);
  140. assert(mLara < (int)getWorld().sizeEntity());
  141. return getWorld().getEntity(mLara);
  142. }
  143. void Game::processSprites() {
  144. for (int i = 0; i < (mTombRaider.NumItems() - 1); i++) {
  145. if ((mTombRaider.Engine() == TR_VERSION_1) && (mTombRaider.Item()[i].intensity1 == -1))
  146. continue;
  147. for (int j = 0; j < mTombRaider.NumSpriteSequences(); j++) {
  148. if (mTombRaider.SpriteSequence()[j].object_id == mTombRaider.Item()[i].object_id)
  149. getWorld().addSprite(*new SpriteSequence(mTombRaider, i, j));
  150. }
  151. }
  152. getConsole().print("Found %d sprites.", mTombRaider.NumSpriteSequences());
  153. }
  154. void Game::processRooms() {
  155. for (int index = 0; index < mTombRaider.NumRooms(); index++)
  156. getWorld().addRoom(*new Room(mTombRaider, index));
  157. getConsole().print("Found %d rooms.", mTombRaider.NumRooms());
  158. }
  159. void Game::processModels() {
  160. for (int index = 0; index < mTombRaider.getMeshCount(); index++)
  161. getWorld().addStaticMesh(*new StaticMesh(mTombRaider, index));
  162. getConsole().print("Found %d meshes.", mTombRaider.getMeshCount());
  163. }
  164. void Game::processPakSounds()
  165. {
  166. unsigned char *riff;
  167. unsigned int riffSz;
  168. //tr2_sound_source_t *sound;
  169. //tr2_sound_details_t *detail;
  170. //float pos[3];
  171. unsigned int i;
  172. int id;
  173. /* detail
  174. short sample;
  175. short volume;
  176. short sound_range;
  177. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  178. // in this group, bits 0-1: channel number
  179. */
  180. for (i = 0; i < mTombRaider.getSoundSamplesCount(); ++i)
  181. {
  182. mTombRaider.getSoundSample(i, &riffSz, &riff);
  183. getSound().addWave(riff, riffSz, &id, Sound::SoundFlagsNone);
  184. //if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  185. //{
  186. //m_testSFX = id;
  187. //}
  188. delete [] riff;
  189. // sound[i].sound_id; // internal sound index
  190. // sound[i].flags; // 0x40, 0x80, or 0xc0
  191. //pos[0] = sound[i].x;
  192. //pos[1] = sound[i].y;
  193. //pos[2] = sound[i].z;
  194. //getSound().SourceAt(id, pos);
  195. }
  196. getConsole().print("Found %u sound samples.", mTombRaider.getSoundSamplesCount());
  197. }
  198. void Game::processTextures()
  199. {
  200. unsigned char *image;
  201. unsigned char *bumpmap;
  202. int i;
  203. //if ( mTombRaider.getNumBumpMaps())
  204. // gBumpMapStart = mTombRaider.NumTextures();
  205. for (i = 0; i < mTombRaider.NumTextures(); ++i)
  206. {
  207. mTombRaider.Texture(i, &image, &bumpmap);
  208. // Overwrite any previous level textures on load
  209. getRender().loadTexture(image, 256, 256, (mTextureStart - 1) + i);
  210. #ifdef MULTITEXTURE
  211. gMapTex2Bump[(mTextureStart - 1) + i] = -1;
  212. #endif
  213. if (bumpmap)
  214. {
  215. #ifdef MULTITEXTURE
  216. gMapTex2Bump[(mTextureStart - 1) + i] = (mTextureStart - 1) + i +
  217. mTombRaider.NumTextures();
  218. #endif
  219. getRender().loadTexture(bumpmap, 256, 256, (mTextureStart - 1) + i +
  220. mTombRaider.NumTextures());
  221. }
  222. if (image)
  223. delete [] image;
  224. if (bumpmap)
  225. delete [] bumpmap;
  226. }
  227. mTextureOffset = (mTextureStart - 1) + mTombRaider.NumTextures();
  228. getConsole().print("Found %d textures.", mTombRaider.NumTextures());
  229. }
  230. void Game::processMoveables()
  231. {
  232. unsigned int statCount = 0;
  233. tr2_moveable_t *moveable = mTombRaider.Moveable();
  234. tr2_item_t *item = mTombRaider.Item();
  235. tr2_sprite_sequence_t *sprite_sequence = mTombRaider.SpriteSequence();
  236. for (int i = 0; i < mTombRaider.NumItems(); ++i)
  237. {
  238. int j;
  239. int object_id = item[i].object_id;
  240. // It may not be a moveable, test for sprite
  241. if (!(mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1)) {
  242. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j) {
  243. if (sprite_sequence[j].object_id == object_id)
  244. break;
  245. }
  246. // It's not a moveable, skip sprite
  247. if (j < (int)mTombRaider.NumSpriteSequences())
  248. continue;
  249. }
  250. for (j = 0; j < (int)mTombRaider.NumMoveables(); ++j) {
  251. if ((int)moveable[j].object_id == object_id)
  252. break;
  253. }
  254. // It's not a moveable or even a sprite? Skip unknown
  255. if (j == (int)mTombRaider.NumMoveables())
  256. continue;
  257. processMoveable(j, i, object_id);
  258. statCount++;
  259. }
  260. /*
  261. // Get models that aren't items
  262. for (int i = 0; i < mTombRaider.NumMoveables(); ++i)
  263. {
  264. switch ((int)moveable[i].object_id)
  265. {
  266. case 30:
  267. case 2: // Which tr needs this as model again?
  268. processMoveable(i, i, (int)moveable[i].object_id);
  269. break;
  270. default:
  271. switch (mTombRaider.Engine())
  272. {
  273. case TR_VERSION_1:
  274. switch ((int)moveable[i].object_id)
  275. {
  276. case TombRaider1::LaraMutant:
  277. processMoveable(i, i, (int)moveable[i].object_id);
  278. break;
  279. }
  280. break;
  281. case TR_VERSION_4:
  282. switch ((int)moveable[i].object_id)
  283. {
  284. case TR4_PISTOLS_ANIM:
  285. case TR4_UZI_ANIM:
  286. case TR4_SHOTGUN_ANIM:
  287. case TR4_CROSSBOW_ANIM:
  288. case TR4_GRENADE_GUN_ANIM:
  289. case TR4_SIXSHOOTER_ANIM:
  290. processMoveable(i, i, (int)moveable[i].object_id);
  291. break;
  292. }
  293. break;
  294. case TR_VERSION_2:
  295. case TR_VERSION_3:
  296. case TR_VERSION_5:
  297. case TR_VERSION_UNKNOWN:
  298. break;
  299. }
  300. }
  301. }
  302. */
  303. getConsole().print("Found %d moveables.", mTombRaider.NumMoveables() + statCount);
  304. }
  305. // index moveable, i item, sometimes both moveable
  306. // object_id of item or moveable
  307. void Game::processMoveable(int index, int i, int object_id) {
  308. // Check if the SkeletalModel is already cached
  309. bool cached = false;
  310. unsigned int model;
  311. for (model = 0; model < getWorld().sizeSkeletalModel(); model++) {
  312. if (getWorld().getSkeletalModel(model).getId() == object_id) {
  313. cached = true;
  314. break;
  315. }
  316. }
  317. // Create a new SkeletalModel, if needed
  318. if (!cached)
  319. getWorld().addSkeletalModel(*new SkeletalModel(mTombRaider, index, object_id));
  320. // Create a new Entity, using the cached or the new SkeletalModel
  321. Entity &entity = *new Entity(mTombRaider, index, i, model);
  322. getWorld().addEntity(entity);
  323. // Store reference to Lara
  324. if (entity.getObjectId() == 0)
  325. mLara = getWorld().sizeEntity() - 1;
  326. // Store reference to the SkyMesh
  327. if (i == mTombRaider.getSkyModelId())
  328. getRender().setSkyMesh(i, //moveable[i].starting_mesh,
  329. (mTombRaider.Engine() == TR_VERSION_2));
  330. }