doors.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * ===========================================================================
  3. *
  4. * Wolf3D Browser Version GPL Source Code
  5. * Copyright (C) 2012 id Software LLC, a ZeniMax Media company.
  6. *
  7. * This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code").
  8. *
  9. * Wolf3D Browser Source Code is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * Wolf3D Browser Source Code is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License version 2
  20. * along with Wolf3D Browser Source Code. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. * If you have questions concerning this license, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  23. *
  24. * ===========================================================================
  25. */
  26. /**
  27. * @namespace
  28. * @description Door management
  29. */
  30. Wolf.Doors = (function() {
  31. Wolf.setConsts({
  32. CLOSEWALL : Wolf.MINDIST, // Space between wall & player
  33. MAXDOORS : 64, // max number of sliding doors
  34. MAX_DOORS : 256, // jseidelin: doesn't look like this is used?
  35. DOOR_TIMEOUT : 300,
  36. DOOR_MINOPEN : 50,
  37. DOOR_FULLOPEN : 63,
  38. DOOR_VERT : 255,
  39. DOOR_HORIZ : 254,
  40. DOOR_E_VERT : 253,
  41. DOOR_E_HORIZ : 252,
  42. DOOR_G_VERT : 251,
  43. DOOR_G_HORIZ : 250,
  44. DOOR_S_VERT : 249,
  45. DOOR_S_HORIZ : 248,
  46. FIRST_DOOR : 248,
  47. LAST_LOCK : 251,
  48. TEX_DOOR : 98,
  49. // TEX_DOOR : 126,
  50. dr_closing : -1,
  51. dr_closed : 0,
  52. dr_opening : 1,
  53. dr_open : 2
  54. });
  55. Wolf.setConsts({
  56. // texture IDs used by cache routines
  57. TEX_DDOOR : (0 + Wolf.TEX_DOOR), // Simple Door
  58. TEX_PLATE : (2 + Wolf.TEX_DOOR), // Door Plate
  59. TEX_DELEV : (4 + Wolf.TEX_DOOR), // Elevator Door
  60. TEX_DLOCK : (6 + Wolf.TEX_DOOR) // Locked Door
  61. });
  62. /**
  63. * @description Reset doors in the level
  64. * @memberOf Wolf.Doors
  65. * @param {object} level The level object.
  66. */
  67. function reset(level) {
  68. level.state.numDoors = 0;
  69. for (var x=0;x<64;x++) {
  70. level.state.doorMap[x] = [];
  71. for (var y=0;y<64;y++) {
  72. level.state.doorMap[x][y] = 0;
  73. }
  74. }
  75. }
  76. /**
  77. * @description Spawn a door at the specified position.
  78. * @memberOf Wolf.Doors
  79. * @param {object} level The level object.
  80. * @param {number} x The x coordinate.
  81. * @param {number} y The y coordinate.
  82. * @param {number} type The door type.
  83. * @returns {number} The index of the new door.
  84. */
  85. function spawn(level, x, y, type) {
  86. if (level.state.numDoors >= Wolf.MAXDOORS) {
  87. throw new Error("Too many Doors on level!");
  88. }
  89. var door = level.state.doorMap[x][y] = {
  90. type : -1,
  91. vertical : 0,
  92. texture : -1,
  93. ticcount : 0
  94. };
  95. switch(type) {
  96. case 0x5A:
  97. door.type = Wolf.DOOR_VERT;
  98. door.vertical = true;
  99. door.texture = Wolf.TEX_DDOOR + 1;
  100. break;
  101. case 0x5B:
  102. door.type = Wolf.DOOR_HORIZ;
  103. door.vertical = false;
  104. door.texture = Wolf.TEX_DDOOR;
  105. break;
  106. case 0x5C:
  107. door.type = Wolf.DOOR_G_VERT;
  108. door.vertical = true;
  109. door.texture = Wolf.TEX_DLOCK;
  110. break;
  111. case 0x5D:
  112. door.type = Wolf.DOOR_G_HORIZ;
  113. door.vertical = false;
  114. door.texture = Wolf.TEX_DLOCK;
  115. break;
  116. case 0x5E:
  117. door.type = Wolf.DOOR_S_VERT;
  118. door.vertical = true;
  119. door.texture = Wolf.TEX_DLOCK + 1;
  120. break;
  121. case 0x5F:
  122. door.type = Wolf.DOOR_S_HORIZ;
  123. door.vertical = false;
  124. door.texture = Wolf.TEX_DLOCK + 1;
  125. break;
  126. case 0x64:
  127. door.type = Wolf.DOOR_E_VERT;
  128. door.vertical = true;
  129. door.texture = Wolf.TEX_DELEV + 1;
  130. break;
  131. case 0x65:
  132. door.type = Wolf.DOOR_E_HORIZ;
  133. door.vertical = false;
  134. door.texture = Wolf.TEX_DELEV;
  135. break;
  136. default:
  137. throw new Error("Unknown door type: " + type);
  138. }
  139. door.tile = {
  140. x : x,
  141. y : y
  142. };
  143. door.action = Wolf.dr_closed;
  144. level.state.doors[level.state.numDoors] = door;
  145. level.state.numDoors++;
  146. return level.state.numDoors - 1;
  147. }
  148. /**
  149. * @description Check to see if a door is open. If there are no doors in tile assume a closed door!
  150. * @memberOf Wolf.Doors
  151. * @param {object} doors The door object.
  152. * @returns {number} DOOR_FULLOPEN if door is opened,
  153. 0 if door is closed,
  154. >0 <DOOR_FULLOPEN if partially opened.
  155. */
  156. function opened(door) {
  157. return door.action == Wolf.dr_open ? Wolf.DOOR_FULLOPEN : door.ticcount;
  158. }
  159. /**
  160. * @description Process door actions.
  161. * @memberOf Wolf.Doors
  162. * @param {object} level The level object
  163. * @param {object} player The player object
  164. * @param {number} tics Tics since last
  165. */
  166. function process(level, player, tics) {
  167. if (player.playstate == Wolf.ex_victory) {
  168. return;
  169. }
  170. for (var n=0;n<level.state.numDoors;++n) {
  171. var door = level.state.doors[n],
  172. doorPos = {
  173. x : Wolf.TILE2POS(door.tile.x),
  174. y : Wolf.TILE2POS(door.tile.y)
  175. };
  176. switch (door.action) {
  177. case Wolf.dr_closed: // this door is closed!
  178. continue;
  179. case Wolf.dr_opening:
  180. if (door.ticcount >= Wolf.DOOR_FULLOPEN) { // door fully opened!
  181. door.action = Wolf.dr_open;
  182. door.ticcount = 0;
  183. } else { // opening!
  184. if (door.ticcount == 0) {
  185. // door is just starting to open, so connect the areas
  186. Wolf.Areas.join(level, door.area1, door.area2);
  187. Wolf.Areas.connect(level, player.areanumber);
  188. if (level.state.areabyplayer[door.area1]) { // Door Opening sound!
  189. Wolf.Sound.startSound(player.position, doorPos, 1, Wolf.CHAN_AUTO, "sfx/010.wav", 1, Wolf.ATTN_STATIC, 0);
  190. }
  191. }
  192. door.ticcount += tics;
  193. if (door.ticcount > Wolf.DOOR_FULLOPEN) {
  194. door.ticcount = Wolf.DOOR_FULLOPEN;
  195. }
  196. }
  197. break;
  198. case Wolf.dr_closing:
  199. if (door.ticcount <= 0) { // door fully closed! disconnect areas!
  200. Wolf.Areas.disconnect(level, door.area1, door.area2);
  201. Wolf.Areas.connect(level, player.areanumber);
  202. door.ticcount = 0;
  203. door.action = Wolf.dr_closed;
  204. } else { // closing!
  205. if (door.ticcount == Wolf.DOOR_FULLOPEN) {
  206. if (level.state.areabyplayer[door.area1]) { // Door Closing sound!
  207. Wolf.Sound.startSound(player.position, doorPos, 1, Wolf.CHAN_AUTO, "sfx/007.wav", 1, Wolf.ATTN_STATIC, 0);
  208. }
  209. }
  210. door.ticcount -= tics;
  211. if (door.ticcount < 0) {
  212. door.ticcount = 0;
  213. }
  214. }
  215. break;
  216. case Wolf.dr_open:
  217. if (door.ticcount > Wolf.DOOR_MINOPEN) {
  218. // If player or something is in door do not close it!
  219. if (!canCloseDoor(level, player, door.tile.x, door.tile.y, door.vertical)) {
  220. door.ticcount = Wolf.DOOR_MINOPEN; // do not close door immediately!
  221. }
  222. }
  223. if (door.ticcount >= Wolf.DOOR_TIMEOUT) {
  224. // Door timeout, time to close it!
  225. door.action = Wolf.dr_closing;
  226. door.ticcount = Wolf.DOOR_FULLOPEN;
  227. } else {
  228. // Increase timeout!
  229. door.ticcount += tics;
  230. }
  231. break;
  232. } // End switch lvldoors->Doors[ n ].action
  233. } // End for n = 0 ; n < lvldoors->numDoors ; ++n
  234. }
  235. /**
  236. * @description Set the areas doors in a level
  237. * @memberOf Wolf.Doors
  238. * @param {object} level The level object.
  239. * @param {array} areas The areas map.
  240. */
  241. function setAreas(level) {
  242. var n, x, y,
  243. door;
  244. for (n=0; n<level.state.numDoors ; ++n){
  245. door = level.state.doors[n];
  246. x = door.tile.x;
  247. y = door.tile.y;
  248. if (door.vertical) {
  249. door.area1 = level.areas[x + 1][y] >= 0 ? level.areas[x + 1][y] : 0;
  250. door.area2 = level.areas[x - 1][y] >= 0 ? level.areas[x - 1][y] : 0;
  251. } else {
  252. door.area1 = level.areas[x][y + 1] >= 0 ? level.areas[x][y + 1] : 0;
  253. door.area2 = level.areas[x][y - 1] >= 0 ? level.areas[x][y - 1] : 0;
  254. }
  255. }
  256. }
  257. /**
  258. * @description Open a door
  259. * @memberOf Wolf.Doors
  260. * @param {object} doors The door object.
  261. */
  262. function open(door) {
  263. if (door.action == Wolf.dr_open) {
  264. door.ticcount = 0; // reset opened time
  265. } else {
  266. door.action = Wolf.dr_opening; // start opening it
  267. }
  268. }
  269. /**
  270. * @description Change the state of a door
  271. * @private
  272. * @param {object} level The level object.
  273. * @param {object} player The player object.
  274. * @param {object} doors The door object.
  275. */
  276. function changeDoorState(level, player, door) {
  277. if (door.action < Wolf.dr_opening ) {
  278. open(door);
  279. } else if (door.action == Wolf.dr_open && canCloseDoor(level, player, door.tile.x, door.tile.y, door.vertical)) {
  280. // !@# for the iphone with automatic using, don't allow any door close actions
  281. // Door->action = dr_closing;
  282. // Door->ticcount = DOOR_FULLOPEN;
  283. }
  284. }
  285. function canCloseDoor(level, player, x, y, vert ) {
  286. var n,
  287. tileX = Wolf.POS2TILE(player.position.x),
  288. tileY = Wolf.POS2TILE(player.position.y),
  289. guard;
  290. if (tileX == x && tileY == y ) {
  291. return false;
  292. }
  293. if (vert) {
  294. if (tileY == y) {
  295. if (Wolf.POS2TILE(player.position.x + Wolf.CLOSEWALL) == x) {
  296. return false;
  297. }
  298. if (Wolf.POS2TILE(player.position.x - Wolf.CLOSEWALL) == x) {
  299. return false;
  300. }
  301. }
  302. for (n = 0; n<level.state.numGuards;++n) {
  303. guard = level.state.guards[n];
  304. if (guard.tile.x == x && guard.tile.y == y ) {
  305. return false; // guard in door
  306. }
  307. if (guard.tile.x == x - 1 && guard.tile.y == y && Wolf.POS2TILE(guard.x + Wolf.CLOSEWALL) == x) {
  308. return false; // guard in door
  309. }
  310. if (guard.tile.x == x + 1 && guard.tile.y == y && Wolf.POS2TILE(guard.x - Wolf.CLOSEWALL) == x) {
  311. return false; // guard in door
  312. }
  313. }
  314. } else {
  315. if (tileX == x) {
  316. if (Wolf.POS2TILE(player.position.y + Wolf.CLOSEWALL) == y) {
  317. return false;
  318. }
  319. if (Wolf.POS2TILE(player.position.y - Wolf.CLOSEWALL) == y) {
  320. return false;
  321. }
  322. }
  323. for (n = 0; n<level.state.numGuards;++n) {
  324. var guard = level.state.guards[n];
  325. if (guard.tile.x == x && guard.tile.y == y ) {
  326. return false; // guard in door
  327. }
  328. if (guard.tile.x == x && guard.tile.y == y - 1 && Wolf.POS2TILE(guard.y + Wolf.CLOSEWALL) == y) {
  329. return false; // guard in door
  330. }
  331. if (guard.tile.x == x && guard.tile.y == y + 1 && Wolf.POS2TILE(guard.y - Wolf.CLOSEWALL) == y) {
  332. return false; // guard in door
  333. }
  334. }
  335. }
  336. return true;
  337. }
  338. /**
  339. * @description Try to use a door with keys that the player has.
  340. * @memberOf Wolf.Doors
  341. * @param {object} level The level object
  342. * @param {object} player The player object
  343. * @param {object} door The door object
  344. * @returns {boolean} Always returns true.
  345. */
  346. function tryUse(level, player, door ) {
  347. switch (door.type) {
  348. case Wolf.DOOR_VERT:
  349. case Wolf.DOOR_HORIZ:
  350. case Wolf.DOOR_E_VERT:
  351. case Wolf.DOOR_E_HORIZ:
  352. changeDoorState(level, player, door); // does not require key!
  353. break;
  354. case Wolf.DOOR_G_VERT:
  355. case Wolf.DOOR_G_HORIZ:
  356. if (player.items & Wolf.ITEM_KEY_1) {
  357. changeDoorState(level, player, door);
  358. } else {
  359. Wolf.Game.notify("You need a gold key");
  360. }
  361. break;
  362. case Wolf.DOOR_S_VERT:
  363. case Wolf.DOOR_S_HORIZ:
  364. if (player.items & Wolf.ITEM_KEY_2) {
  365. changeDoorState(level, player, door);
  366. } else {
  367. Wolf.Game.notify("You need a silver key");
  368. }
  369. break;
  370. }
  371. return true; // FIXME
  372. }
  373. return {
  374. reset : reset,
  375. spawn : spawn,
  376. opened : opened,
  377. open : open,
  378. tryUse : tryUse,
  379. process : process,
  380. setAreas : setAreas
  381. };
  382. })();