├── COPYING.txt ├── README.txt ├── index.html ├── js ├── actorai.js ├── actors.js ├── actstat.js ├── ai.js ├── angle.js ├── areas.js ├── doors.js ├── episodes.js ├── file.js ├── game.js ├── input.js ├── level.js ├── load.js ├── maps.sample.js ├── math.js ├── menu.js ├── player.js ├── powerups.js ├── pushwall.js ├── random.js ├── raycaster.js ├── renderer.js ├── requestanimframe.js ├── sound.js ├── sprites.js ├── weapon.js └── wolf.js ├── styles.css └── wolf3d.html /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | 60 | GNU GENERAL PUBLIC LICENSE 61 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 62 | 63 | 0. This License applies to any program or other work which contains 64 | a notice placed by the copyright holder saying it may be distributed 65 | under the terms of this General Public License. The "Program", below, 66 | refers to any such program or work, and a "work based on the Program" 67 | means either the Program or any derivative work under copyright law: 68 | that is to say, a work containing the Program or a portion of it, 69 | either verbatim or with modifications and/or translated into another 70 | language. (Hereinafter, translation is included without limitation in 71 | the term "modification".) Each licensee is addressed as "you". 72 | 73 | Activities other than copying, distribution and modification are not 74 | covered by this License; they are outside its scope. The act of 75 | running the Program is not restricted, and the output from the Program 76 | is covered only if its contents constitute a work based on the 77 | Program (independent of having been made by running the Program). 78 | Whether that is true depends on what the Program does. 79 | 80 | 1. You may copy and distribute verbatim copies of the Program's 81 | source code as you receive it, in any medium, provided that you 82 | conspicuously and appropriately publish on each copy an appropriate 83 | copyright notice and disclaimer of warranty; keep intact all the 84 | notices that refer to this License and to the absence of any warranty; 85 | and give any other recipients of the Program a copy of this License 86 | along with the Program. 87 | 88 | You may charge a fee for the physical act of transferring a copy, and 89 | you may at your option offer warranty protection in exchange for a fee. 90 | 91 | 2. You may modify your copy or copies of the Program or any portion 92 | of it, thus forming a work based on the Program, and copy and 93 | distribute such modifications or work under the terms of Section 1 94 | above, provided that you also meet all of these conditions: 95 | 96 | a) You must cause the modified files to carry prominent notices 97 | stating that you changed the files and the date of any change. 98 | 99 | b) You must cause any work that you distribute or publish, that in 100 | whole or in part contains or is derived from the Program or any 101 | part thereof, to be licensed as a whole at no charge to all third 102 | parties under the terms of this License. 103 | 104 | c) If the modified program normally reads commands interactively 105 | when run, you must cause it, when started running for such 106 | interactive use in the most ordinary way, to print or display an 107 | announcement including an appropriate copyright notice and a 108 | notice that there is no warranty (or else, saying that you provide 109 | a warranty) and that users may redistribute the program under 110 | these conditions, and telling the user how to view a copy of this 111 | License. (Exception: if the Program itself is interactive but 112 | does not normally print such an announcement, your work based on 113 | the Program is not required to print an announcement.) 114 | 115 | 116 | These requirements apply to the modified work as a whole. If 117 | identifiable sections of that work are not derived from the Program, 118 | and can be reasonably considered independent and separate works in 119 | themselves, then this License, and its terms, do not apply to those 120 | sections when you distribute them as separate works. But when you 121 | distribute the same sections as part of a whole which is a work based 122 | on the Program, the distribution of the whole must be on the terms of 123 | this License, whose permissions for other licensees extend to the 124 | entire whole, and thus to each and every part regardless of who wrote it. 125 | 126 | Thus, it is not the intent of this section to claim rights or contest 127 | your rights to work written entirely by you; rather, the intent is to 128 | exercise the right to control the distribution of derivative or 129 | collective works based on the Program. 130 | 131 | In addition, mere aggregation of another work not based on the Program 132 | with the Program (or with a work based on the Program) on a volume of 133 | a storage or distribution medium does not bring the other work under 134 | the scope of this License. 135 | 136 | 3. You may copy and distribute the Program (or a work based on it, 137 | under Section 2) in object code or executable form under the terms of 138 | Sections 1 and 2 above provided that you also do one of the following: 139 | 140 | a) Accompany it with the complete corresponding machine-readable 141 | source code, which must be distributed under the terms of Sections 142 | 1 and 2 above on a medium customarily used for software interchange; or, 143 | 144 | b) Accompany it with a written offer, valid for at least three 145 | years, to give any third party, for a charge no more than your 146 | cost of physically performing source distribution, a complete 147 | machine-readable copy of the corresponding source code, to be 148 | distributed under the terms of Sections 1 and 2 above on a medium 149 | customarily used for software interchange; or, 150 | 151 | c) Accompany it with the information you received as to the offer 152 | to distribute corresponding source code. (This alternative is 153 | allowed only for noncommercial distribution and only if you 154 | received the program in object code or executable form with such 155 | an offer, in accord with Subsection b above.) 156 | 157 | The source code for a work means the preferred form of the work for 158 | making modifications to it. For an executable work, complete source 159 | code means all the source code for all modules it contains, plus any 160 | associated interface definition files, plus the scripts used to 161 | control compilation and installation of the executable. However, as a 162 | special exception, the source code distributed need not include 163 | anything that is normally distributed (in either source or binary 164 | form) with the major components (compiler, kernel, and so on) of the 165 | operating system on which the executable runs, unless that component 166 | itself accompanies the executable. 167 | 168 | If distribution of executable or object code is made by offering 169 | access to copy from a designated place, then offering equivalent 170 | access to copy the source code from the same place counts as 171 | distribution of the source code, even though third parties are not 172 | compelled to copy the source along with the object code. 173 | 174 | 175 | 4. You may not copy, modify, sublicense, or distribute the Program 176 | except as expressly provided under this License. Any attempt 177 | otherwise to copy, modify, sublicense or distribute the Program is 178 | void, and will automatically terminate your rights under this License. 179 | However, parties who have received copies, or rights, from you under 180 | this License will not have their licenses terminated so long as such 181 | parties remain in full compliance. 182 | 183 | 5. You are not required to accept this License, since you have not 184 | signed it. However, nothing else grants you permission to modify or 185 | distribute the Program or its derivative works. These actions are 186 | prohibited by law if you do not accept this License. Therefore, by 187 | modifying or distributing the Program (or any work based on the 188 | Program), you indicate your acceptance of this License to do so, and 189 | all its terms and conditions for copying, distributing or modifying 190 | the Program or works based on it. 191 | 192 | 6. Each time you redistribute the Program (or any work based on the 193 | Program), the recipient automatically receives a license from the 194 | original licensor to copy, distribute or modify the Program subject to 195 | these terms and conditions. You may not impose any further 196 | restrictions on the recipients' exercise of the rights granted herein. 197 | You are not responsible for enforcing compliance by third parties to 198 | this License. 199 | 200 | 7. If, as a consequence of a court judgment or allegation of patent 201 | infringement or for any other reason (not limited to patent issues), 202 | conditions are imposed on you (whether by court order, agreement or 203 | otherwise) that contradict the conditions of this License, they do not 204 | excuse you from the conditions of this License. If you cannot 205 | distribute so as to satisfy simultaneously your obligations under this 206 | License and any other pertinent obligations, then as a consequence you 207 | may not distribute the Program at all. For example, if a patent 208 | license would not permit royalty-free redistribution of the Program by 209 | all those who receive copies directly or indirectly through you, then 210 | the only way you could satisfy both it and this License would be to 211 | refrain entirely from distribution of the Program. 212 | 213 | If any portion of this section is held invalid or unenforceable under 214 | any particular circumstance, the balance of the section is intended to 215 | apply and the section as a whole is intended to apply in other 216 | circumstances. 217 | 218 | It is not the purpose of this section to induce you to infringe any 219 | patents or other property right claims or to contest validity of any 220 | such claims; this section has the sole purpose of protecting the 221 | integrity of the free software distribution system, which is 222 | implemented by public license practices. Many people have made 223 | generous contributions to the wide range of software distributed 224 | through that system in reliance on consistent application of that 225 | system; it is up to the author/donor to decide if he or she is willing 226 | to distribute software through any other system and a licensee cannot 227 | impose that choice. 228 | 229 | This section is intended to make thoroughly clear what is believed to 230 | be a consequence of the rest of this License. 231 | 232 | 233 | 8. If the distribution and/or use of the Program is restricted in 234 | certain countries either by patents or by copyrighted interfaces, the 235 | original copyright holder who places the Program under this License 236 | may add an explicit geographical distribution limitation excluding 237 | those countries, so that distribution is permitted only in or among 238 | countries not thus excluded. In such case, this License incorporates 239 | the limitation as if written in the body of this License. 240 | 241 | 9. The Free Software Foundation may publish revised and/or new versions 242 | of the General Public License from time to time. Such new versions will 243 | be similar in spirit to the present version, but may differ in detail to 244 | address new problems or concerns. 245 | 246 | Each version is given a distinguishing version number. If the Program 247 | specifies a version number of this License which applies to it and "any 248 | later version", you have the option of following the terms and conditions 249 | either of that version or of any later version published by the Free 250 | Software Foundation. If the Program does not specify a version number of 251 | this License, you may choose any version ever published by the Free Software 252 | Foundation. 253 | 254 | 10. If you wish to incorporate parts of the Program into other free 255 | programs whose distribution conditions are different, write to the author 256 | to ask for permission. For software which is copyrighted by the Free 257 | Software Foundation, write to the Free Software Foundation; we sometimes 258 | make exceptions for this. Our decision will be guided by the two goals 259 | of preserving the free status of all derivatives of our free software and 260 | of promoting the sharing and reuse of software generally. 261 | 262 | NO WARRANTY 263 | 264 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 265 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 266 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 267 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 268 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 269 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 270 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 271 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 272 | REPAIR OR CORRECTION. 273 | 274 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 275 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 276 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 277 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 278 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 279 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 280 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 281 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 282 | POSSIBILITY OF SUCH DAMAGES. 283 | 284 | END OF TERMS AND CONDITIONS 285 | 286 | 287 | How to Apply These Terms to Your New Programs 288 | 289 | If you develop a new program, and you want it to be of the greatest 290 | possible use to the public, the best way to achieve this is to make it 291 | free software which everyone can redistribute and change under these terms. 292 | 293 | To do so, attach the following notices to the program. It is safest 294 | to attach them to the start of each source file to most effectively 295 | convey the exclusion of warranty; and each file should have at least 296 | the "copyright" line and a pointer to where the full notice is found. 297 | 298 | 299 | Copyright (C) 300 | 301 | This program is free software; you can redistribute it and/or modify 302 | it under the terms of the GNU General Public License as published by 303 | the Free Software Foundation; either version 2 of the License, or 304 | (at your option) any later version. 305 | 306 | This program is distributed in the hope that it will be useful, 307 | but WITHOUT ANY WARRANTY; without even the implied warranty of 308 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 309 | GNU General Public License for more details. 310 | 311 | You should have received a copy of the GNU General Public License 312 | along with this program; if not, write to the Free Software 313 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 314 | 315 | 316 | Also add information on how to contact you by electronic and paper mail. 317 | 318 | If the program is interactive, make it output a short notice like this 319 | when it starts in an interactive mode: 320 | 321 | Gnomovision version 69, Copyright (C) year name of author 322 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 323 | This is free software, and you are welcome to redistribute it 324 | under certain conditions; type `show c' for details. 325 | 326 | The hypothetical commands `show w' and `show c' should show the appropriate 327 | parts of the General Public License. Of course, the commands you use may 328 | be called something other than `show w' and `show c'; they could even be 329 | mouse-clicks or menu items--whatever suits your program. 330 | 331 | You should also get your employer (if you work as a programmer) or your 332 | school, if any, to sign a "copyright disclaimer" for the program, if 333 | necessary. Here is a sample; alter the names: 334 | 335 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 336 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 337 | 338 | , 1 April 1989 339 | Ty Coon, President of Vice 340 | 341 | This General Public License does not permit incorporating your program into 342 | proprietary programs. If your program is a subroutine library, you may 343 | consider it more useful to permit linking proprietary applications with the 344 | library. If this is what you want to do, use the GNU Library General 345 | Public License instead of this License. -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | WOLF3D Browser Version GPL source release 2 | =============================================== 3 | 4 | This file contains the following sections: 5 | 6 | GENERAL NOTES 7 | LICENSE 8 | 9 | GENERAL NOTES 10 | ============= 11 | 12 | WOLF3D Browser Version is a free release, and can be downloaded from 13 | https://github.com/id-Software/wolf3d-browser 14 | 15 | This source release does not contain any game data, the game data remains subject to the original EULA and applicable law. 16 | 17 | 18 | LICENSE 19 | ======= 20 | 21 | See COPYING.txt for the GNU GENERAL PUBLIC LICENSE. If COPYING.txt does not accompany, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 | 23 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | Test Page 11 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /js/actors.js: -------------------------------------------------------------------------------- 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 . 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 | /** 28 | * @namespace 29 | * @description Actors 30 | */ 31 | Wolf.Actors = (function() { 32 | 33 | Wolf.setConsts({ 34 | SPDPATROL : 512, 35 | SPDDOG : 1500, 36 | 37 | FL_SHOOTABLE : 1, 38 | FL_BONUS : 2, 39 | FL_NEVERMARK : 4, 40 | FL_VISABLE : 8, 41 | FL_ATTACKMODE : 16, 42 | FL_FIRSTATTACK : 32, 43 | FL_AMBUSH : 64, 44 | FL_NONMARK : 128, 45 | 46 | MAX_GUARDS : 255, 47 | NUMENEMIES : 31, 48 | NUMSTATES : 34, 49 | 50 | MINACTORDIST : 0x10000 51 | }); 52 | 53 | Wolf.setConsts({ 54 | en_guard : 0, 55 | en_officer : 1, 56 | en_ss : 2, 57 | en_dog : 3, 58 | en_boss : 4, 59 | en_schabbs : 5, 60 | en_fake : 6, 61 | en_mecha : 7, 62 | en_hitler : 8, 63 | en_mutant : 9, 64 | en_blinky : 10, 65 | en_clyde : 11, 66 | en_pinky : 12, 67 | en_inky : 13, 68 | en_gretel : 14, 69 | en_gift : 15, 70 | en_fat : 16, 71 | // --- Projectiles 72 | en_needle : 17, 73 | en_fire : 18, 74 | en_rocket : 19, 75 | en_smoke : 20, 76 | en_bj : 21, 77 | // --- Spear of destiny! 78 | en_spark : 22, 79 | en_hrocket : 23, 80 | en_hsmoke : 24, 81 | 82 | en_spectre : 25, 83 | en_angel : 26, 84 | en_trans : 27, 85 | en_uber : 28, 86 | en_will : 29, 87 | en_death : 30 88 | }); 89 | 90 | Wolf.setConsts({ 91 | st_stand : 0, 92 | st_path1 : 1, 93 | st_path1s : 2, 94 | st_path2 : 3, 95 | st_path3 : 4, 96 | st_path3s : 5, 97 | st_path4 : 6, 98 | st_pain : 7, 99 | st_pain1 : 8, 100 | st_shoot1 : 9, 101 | st_shoot2 : 10, 102 | st_shoot3 : 11, 103 | st_shoot4 : 12, 104 | st_shoot5 : 13, 105 | st_shoot6 : 14, 106 | st_shoot7 : 15, 107 | st_shoot8 : 16, 108 | st_shoot9 : 17, 109 | st_chase1 : 18, 110 | st_chase1s : 19, 111 | st_chase2 : 20, 112 | st_chase3 : 21, 113 | st_chase3s : 22, 114 | st_chase4 : 23, 115 | st_die1 : 24, 116 | st_die2 : 25, 117 | st_die3 : 26, 118 | st_die4 : 27, 119 | st_die5 : 28, 120 | st_die6 : 29, 121 | st_die7 : 30, 122 | st_die8 : 31, 123 | st_die9 : 32, 124 | st_dead : 33, 125 | st_remove : 34 126 | }); 127 | 128 | var add8dir = [4, 5, 6, 7, 0, 1, 2, 3, 0], 129 | r_add8dir = [4, 7, 6, 5, 0, 1, 2, 3, 0]; 130 | 131 | /** 132 | * @description Create new actor. 133 | * @memberOf Wolf.Actors 134 | * @param {object} level The level object. 135 | * @returns {object} The new actor object. 136 | */ 137 | function getNewActor(level) { 138 | 139 | if (level.state.numGuards > Wolf.MAX_GUARDS) { 140 | return null; 141 | } 142 | 143 | var actor = { 144 | x : 0, 145 | y : 0, 146 | angle : 0, 147 | type : 0, 148 | health : 0, 149 | max_health : 0, 150 | speed : 0, 151 | ticcount : 0, 152 | temp2 : 0, 153 | distance : 0, 154 | tile : { 155 | x : 0, 156 | y : 0 157 | }, 158 | areanumber : 0, 159 | waitfordoorx : 0, 160 | waitfordoory : 0, // waiting on this door if non 0 161 | flags : 0, // FL_SHOOTABLE, etc 162 | state : 0, 163 | dir : 0, 164 | sprite : 0 165 | }; 166 | level.state.guards[level.state.numGuards++] = actor; 167 | 168 | return actor; 169 | } 170 | 171 | /** 172 | * @description Process a single actor. 173 | * @private 174 | * @param {object} ent The actor object. 175 | * @param {object} level The level object. 176 | * @param {object} player The player object. 177 | * @param {number} tics The number of tics. 178 | * @returns {boolean} False if actor should be removed, otherwise true. 179 | */ 180 | function doGuard(ent, game, tics) { // FIXME: revise! 181 | var think; 182 | 183 | //assert( ent->tilex >= 0 && ent->tilex < 64 ); 184 | //assert( ent->tiley >= 0 && ent->tiley < 64 ); 185 | //assert( ent->dir >= 0 && ent->dir <= 8 ); 186 | 187 | 188 | // ticcounts fire discrete actions separate from think functions 189 | if (ent.ticcount) { 190 | ent.ticcount -= tics; 191 | 192 | while (ent.ticcount <= 0) { 193 | //assert( ent->type >= 0 && ent->type < NUMENEMIES ); 194 | //assert( ent->state >= 0 && ent->state < NUMSTATES ); 195 | 196 | think = Wolf.objstate[ent.type][ent.state].action; // end of state action 197 | if (think) { 198 | think(ent, game, tics); 199 | if (ent.state == Wolf.st_remove) { 200 | return false; 201 | } 202 | } 203 | 204 | ent.state = Wolf.objstate[ent.type][ent.state].next_state; 205 | if (ent.state == Wolf.st_remove) { 206 | return false; 207 | } 208 | 209 | if (!Wolf.objstate[ent.type][ent.state].timeout) { 210 | ent.ticcount = 0; 211 | break; 212 | } 213 | 214 | ent.ticcount += Wolf.objstate[ent.type][ent.state].timeout; 215 | } 216 | } 217 | // 218 | // think 219 | // 220 | //assert( ent->type >= 0 && ent->type < NUMENEMIES ); 221 | //assert( ent->state >= 0 && ent->state < NUMSTATES ); 222 | think = Wolf.objstate[ent.type][ent.state].think; 223 | 224 | if (think) { 225 | think(ent, game, tics); 226 | if (ent.state == Wolf.st_remove) { 227 | return false; 228 | } 229 | } 230 | 231 | return true; 232 | } 233 | 234 | 235 | /** 236 | * @description Changes guard's state to that defined in newState. 237 | * @memberOf Wolf.Actors 238 | * @param {object} ent The actor object. 239 | * @param {number} newState The new state. 240 | */ 241 | function stateChange(ent, newState) { 242 | ent.state = newState; 243 | // assert( ent->type >= 0 && ent->type < NUMENEMIES ); 244 | if (newState == Wolf.st_remove) { 245 | ent.ticcount = 0; 246 | } else { 247 | // assert( ent->state >= 0 && ent->state < NUMSTATES ); 248 | ent.ticcount = Wolf.objstate[ent.type][ent.state].timeout; //0; 249 | } 250 | } 251 | 252 | /** 253 | * @description Process all the enemy actors. 254 | * @memberOf Wolf.Actors 255 | * @param {object} level The level object. 256 | * @param {object} player The player object. 257 | * @param {number} tics The number of tics. 258 | */ 259 | function process(game, tics) { 260 | var level = game.level, 261 | player = game.player, 262 | n, tex, guard, 263 | liveGuards = []; 264 | 265 | for (n = 0 ; n < level.state.numGuards ; ++n ) { 266 | guard = level.state.guards[n]; 267 | 268 | if (!doGuard(guard, game, tics)) { 269 | // remove guard from the game forever! 270 | // remove(game, guards[n--]); 271 | Wolf.Sprites.remove(level, guard.sprite); 272 | level.state.guards[n] = null; 273 | continue; 274 | } 275 | 276 | Wolf.Sprites.setPos(level, guard.sprite, guard.x, guard.y, guard.angle); 277 | 278 | tex = Wolf.objstate[guard.type][guard.state].texture; 279 | 280 | if (Wolf.objstate[guard.type][guard.state].rotate) { 281 | if (guard.type == Wolf.en_rocket || guard.type == Wolf.en_hrocket) { 282 | tex += r_add8dir[Wolf.Math.get8dir( Wolf.Angle.distCW(Wolf.FINE2RAD(player.angle), Wolf.FINE2RAD(guard.angle)))]; 283 | } else { 284 | tex += add8dir[Wolf.Math.get8dir( Wolf.Angle.distCW(Wolf.FINE2RAD(player.angle), Wolf.FINE2RAD(guard.angle)))]; 285 | } 286 | } 287 | Wolf.Sprites.setTex(level, guard.sprite, 0, tex); 288 | } 289 | 290 | for (n = 0 ; n < level.state.numGuards ; ++n ) { 291 | if (level.state.guards[n]) { 292 | liveGuards.push(level.state.guards[n]); 293 | } 294 | } 295 | level.state.guards = liveGuards; 296 | level.state.numGuards = liveGuards.length; 297 | } 298 | 299 | /** 300 | * @description Reset and clear the enemy actors in the level. 301 | * @memberOf Wolf.Actors 302 | * @param {object} level The level object. 303 | */ 304 | function resetGuards(level) { 305 | level.state.guards = []; 306 | level.state.numGuards = 0; 307 | //New = NULL; 308 | } 309 | 310 | /** 311 | * @description Spawn a new enemy actor at the given position. 312 | * @memberOf Wolf.Actors 313 | * @param {object} level The level object. 314 | * @param {number} skill The difficulty level. 315 | * @param {number} which The actor type. 316 | * @param {number} x The x position. 317 | * @param {number} y The y position. 318 | * @param {number} dir The direction. 319 | * @returns {object} The new actor object or null if actor creation failed. 320 | */ 321 | function spawn(level, skill, which, x, y, dir) { 322 | var ent = getNewActor(level); 323 | 324 | if (!ent) { 325 | return null; 326 | } 327 | 328 | ent.x = Wolf.TILE2POS(x); 329 | ent.y = Wolf.TILE2POS(y); 330 | 331 | ent.tile.x = x; 332 | ent.tile.y = y; 333 | 334 | // assert( dir >= 0 && dir <= 4 ); 335 | ent.angle = Wolf.Math.dir4angle[dir]; 336 | ent.dir = Wolf.Math.dir4to8[dir]; 337 | 338 | ent.areanumber = level.areas[x][y]; 339 | 340 | if (ent.areanumber < 0) { 341 | // ambush marker tiles are listed as -3 area 342 | ent.areanumber = 0; 343 | } 344 | 345 | // assert( ent->areanumber >= 0 && ent->areanumber < NUMAREAS ); 346 | ent.type = which; 347 | ent.health = Wolf.starthitpoints[skill][which]; 348 | ent.sprite = Wolf.Sprites.getNewSprite(level); 349 | 350 | return ent; 351 | } 352 | 353 | /** 354 | * @description Spawn a dead guard. 355 | * @memberOf Wolf.Actors 356 | * @param {object} level The level object. 357 | * @param {number} skill The difficulty level. 358 | * @param {number} which The actor type. 359 | * @param {number} x The x position. 360 | * @param {number} y The y position. 361 | */ 362 | function spawnDeadGuard(level, skill, which, x, y) { 363 | var self = spawn(level, skill, which, x, y, Wolf.Math.dir4_nodir); 364 | if (!self) { 365 | return; 366 | } 367 | self.state = Wolf.st_dead; 368 | self.speed = 0; 369 | self.health = 0; 370 | self.ticcount = Wolf.objstate[which][Wolf.st_dead].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_dead].timeout + 1 : 0; 371 | } 372 | 373 | /** 374 | * @description Spawn a patrolling guard. 375 | * @memberOf Wolf.Actors 376 | * @param {object} level The level object. 377 | * @param {number} skill The difficulty level. 378 | * @param {number} which The actor type. 379 | * @param {number} x The x position. 380 | * @param {number} y The y position. 381 | */ 382 | function spawnPatrol(level, skill, which, x, y, dir) { 383 | var self = spawn(level, skill, which, x, y, dir); 384 | if (!self) { 385 | return; 386 | } 387 | 388 | self.state = Wolf.st_path1; 389 | self.speed = (which == Wolf.en_dog) ? Wolf.SPDDOG : Wolf.SPDPATROL; 390 | self.distance = Wolf.TILEGLOBAL; 391 | self.ticcount = Wolf.objstate[which][Wolf.st_path1].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_path1].timeout + 1 : 0; 392 | self.flags |= Wolf.FL_SHOOTABLE; 393 | 394 | level.state.totalMonsters++; 395 | } 396 | 397 | /** 398 | * @description Spawn a standing guard. 399 | * @memberOf Wolf.Actors 400 | * @param {object} level The level object. 401 | * @param {number} skill The difficulty level. 402 | * @param {number} which The actor type. 403 | * @param {number} x The x position. 404 | * @param {number} y The y position. 405 | */ 406 | function spawnStand(level, skill, which, x, y, dir) { 407 | var self = spawn(level, skill, which, x, y, dir); 408 | if (!self) { 409 | return; 410 | } 411 | 412 | self.state = Wolf.st_stand; 413 | self.speed = Wolf.SPDPATROL; 414 | self.ticcount = Wolf.objstate[which][Wolf.st_stand].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_stand].timeout + 1 : 0; 415 | self.flags |= Wolf.FL_SHOOTABLE; 416 | 417 | if (level.tileMap[x][y] & Wolf.AMBUSH_TILE) { 418 | self.flags |= Wolf.FL_AMBUSH; 419 | } 420 | 421 | level.state.totalMonsters++; 422 | } 423 | 424 | function spawnBoss(level, skill, which, x, y) { 425 | var self, 426 | face; 427 | 428 | switch (which) { 429 | case Wolf.en_boss: 430 | case Wolf.en_schabbs: 431 | case Wolf.en_fat: 432 | case Wolf.en_hitler: 433 | face = Wolf.Math.dir4_south; 434 | break; 435 | 436 | case Wolf.en_fake: 437 | case Wolf.en_gretel: 438 | case Wolf.en_gift: 439 | face = Wolf.Math.dir4_north; 440 | break; 441 | 442 | case Wolf.en_trans: 443 | case Wolf.en_uber: 444 | case Wolf.en_will: 445 | case Wolf.en_death: 446 | case Wolf.en_angel: 447 | case Wolf.en_spectre: 448 | face = Wolf.Math.dir4_nodir; 449 | break; 450 | 451 | default: 452 | face = Wolf.Math.dir4_nodir; 453 | break; 454 | } 455 | 456 | self = spawn(level, skill, which, x, y, face); 457 | if (!self) { 458 | return; 459 | } 460 | 461 | self.state = which == Wolf.en_spectre ? Wolf.st_path1 : Wolf.st_stand; 462 | self.speed = Wolf.SPDPATROL; 463 | self.health = Wolf.starthitpoints[skill][which]; 464 | self.ticcount = Wolf.objstate[which][Wolf.st_stand].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_stand].timeout + 1 : 0; 465 | self.flags |= Wolf.FL_SHOOTABLE | Wolf.FL_AMBUSH; 466 | 467 | level.state.totalMonsters++; 468 | } 469 | 470 | 471 | function spawnGhosts(level, skill, which, x, y) { 472 | var self = spawn(level, skill, which, x, y, Wolf.Math.dir4_nodir); 473 | if (!self) { 474 | return; 475 | } 476 | 477 | self.state = Wolf.st_chase1; 478 | self.speed = Wolf.SPDPATROL * 3; 479 | self.health = Wolf.starthitpoints[skill][which]; 480 | self.ticcount = Wolf.objstate[which][Wolf.st_chase1].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_chase1].timeout + 1: 0; 481 | self.flags |= Wolf.FL_AMBUSH; 482 | 483 | level.state.totalMonsters++; 484 | } 485 | 486 | function spawnBJVictory(player, level, skill) { 487 | var x = Wolf.POS2TILE(player.position.x), 488 | y = Wolf.POS2TILE(player.position.y), 489 | bj = spawn(level, skill, Wolf.en_bj, x, y + 1, Wolf.Math.dir4_north); 490 | 491 | if (!bj) { 492 | return; 493 | } 494 | 495 | bj.x = player.position.x; 496 | bj.y = player.position.y; 497 | bj.state = Wolf.st_path1; 498 | bj.speed = Wolf.BJRUNSPEED; 499 | bj.flags = Wolf.FL_NONMARK; // FL_NEVERMARK; 500 | bj.temp2 = 6; 501 | bj.ticcount = 1; 502 | } 503 | 504 | return { 505 | process : process, 506 | resetGuards : resetGuards, 507 | getNewActor : getNewActor, 508 | spawn : spawn, 509 | spawnDeadGuard : spawnDeadGuard, 510 | spawnPatrol : spawnPatrol, 511 | spawnStand : spawnStand, 512 | spawnBoss : spawnBoss, 513 | spawnGhosts : spawnGhosts, 514 | spawnBJVictory : spawnBJVictory, 515 | stateChange : stateChange 516 | }; 517 | 518 | })(); 519 | -------------------------------------------------------------------------------- /js/angle.js: -------------------------------------------------------------------------------- 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 . 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 | 28 | /** 29 | * @namespace 30 | * @description Angle math 31 | */ 32 | Wolf.Angle = (function() { 33 | 34 | Wolf.setConsts({ 35 | DEG2RAD : function(a) { return a * 0.01745329251994329576; }, // a * M_PI / 180.0f 36 | RAD2DEG : function(a) { return a / 0.01745329251994329576; }, // a * 180.0f / M_PI 37 | ANGLE2SHORT : function(x) { return ((x * 65536 / 360)>>0) & 65535; }, 38 | SHORT2ANGLE : function(x) { return x * 360.0 / 65536; } 39 | }); 40 | 41 | /** 42 | * @description Finds the difference between two angles. 43 | * @memberOf Wolf.Angle 44 | * @param {number} angle1 Angle in radians. 45 | * @param {number} angle2 Angle in radians. 46 | * @returns {number} The absolute difference between two angles, this will always be between 0 and 180 degrees. 47 | */ 48 | function diff(angle1, angle2) { 49 | var d; 50 | 51 | if (angle1 > angle2) { 52 | d = angle1 - angle2; 53 | } else { 54 | d = angle2 - angle1; 55 | } 56 | 57 | if (d > Math.PI) { 58 | return 2 * Math.PI - d; 59 | } else { 60 | return d; 61 | } 62 | } 63 | 64 | /** 65 | * @description Clockwise distance between two angles. 66 | * @memberOf Wolf.Angle 67 | * @param {number} angle1 Angle in radians. 68 | * @param {number} angle2 Angle in radians. 69 | * @returns {number} The clockwise distance from angle2 to angle1, this may be greater than 180 degrees. 70 | */ 71 | function distCW(angle1, angle2) { 72 | if (angle1 > angle2) { 73 | return angle1 - angle2; 74 | } else { 75 | return angle1 + 2 * Math.PI - angle2; 76 | } 77 | } 78 | 79 | /** 80 | * @description Linear interpolate between angle from and to by fraction frac. 81 | * @memberOf Wolf.Angle 82 | * @param {number} from Angle in radians. 83 | * @param {number} to Angle in radians. 84 | * @param {number} frac Fraction. 85 | * @returns {number} 86 | */ 87 | function interpolate(from, to, frac) { 88 | var d = diff(from, to) * frac; 89 | 90 | if (distCW(to, from) >= Math.PI) { 91 | return from - diff; 92 | } else { 93 | return from + diff; 94 | } 95 | } 96 | 97 | 98 | /** 99 | * @description Normalize angle. 100 | * @memberOf Wolf.Angle 101 | * @param {number} angle 102 | * @returns {number} 103 | */ 104 | function normalize(angle) { 105 | while (angle < 0) { 106 | angle += (2 * Math.PI); 107 | } 108 | while (angle >= (2 * Math.PI)) { 109 | angle -= (2 * Math.PI); 110 | } 111 | return angle; 112 | } 113 | 114 | 115 | 116 | /** 117 | * @description Linear interpolate allowing for the Modulo 360 problem. 118 | * @memberOf Wolf.Angle 119 | * @param {number} from Angle in radians. 120 | * @param {number} to Angle in radians. 121 | * @param {number} frac fraction. 122 | * @returns {number} 123 | */ 124 | 125 | function lerp(from, to, frac) { 126 | if (to - from > 180) { 127 | to -= 360; 128 | } 129 | if (to - from < -180) { 130 | to += 360; 131 | } 132 | return from + frac * (to - from); 133 | } 134 | 135 | return { 136 | diff : diff, 137 | distCW : distCW, 138 | normalize : normalize, 139 | interpolate : interpolate, 140 | lerp : lerp 141 | } 142 | 143 | })(); -------------------------------------------------------------------------------- /js/areas.js: -------------------------------------------------------------------------------- 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 . 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 | 28 | /** 29 | * @namespace 30 | * @description Area management 31 | */ 32 | Wolf.Areas = (function() { 33 | /* 34 | Notes: 35 | 36 | Open doors connect two areas, so sounds will travel between them and sight 37 | will be checked when the player is in a connected area. 38 | 39 | Areaconnect is incremented/decremented by each door. If >0 they connect. 40 | 41 | Every time a door opens or closes the areabyplayer matrix gets recalculated. 42 | An area is true if it connects with the player's current spor. 43 | 44 | */ 45 | 46 | /** 47 | * @description Initialize areas 48 | * @memberOf Wolf.Areas 49 | * @param {object} levelState The level state object 50 | * @param {number} areanumber Initial area 51 | */ 52 | function init(level, areanumber) { 53 | level.state.areaconnect = []; 54 | level.state.areabyplayer = []; 55 | for (var i=0;i= Wolf.NUMAREAS) { 91 | throw new Error("areanumber >= Wolf.NUMAREAS"); 92 | } 93 | 94 | level.state.areabyplayer = []; 95 | level.state.areabyplayer[areanumber] = true; 96 | 97 | recursiveConnect(level, areanumber); 98 | for (i = 0; i < Wolf.NUMAREAS; i++) { 99 | if (level.state.areabyplayer[i]) { 100 | c++; 101 | } 102 | } 103 | } 104 | 105 | /** 106 | * @description Join ares 107 | * @memberOf Wolf.Areas 108 | * @param {object} level The level object 109 | * @param {number} area1 Area 1 110 | * @param {number} area2 Area 2 111 | */ 112 | function join(level, area1, area2) { 113 | if (area1 < 0 || area1 >= Wolf.NUMAREAS) { 114 | throw new Error("area1 < 0 || area1 >= Wolf.NUMAREAS"); 115 | } 116 | if (area2 < 0 || area2 >= Wolf.NUMAREAS) { 117 | throw new Error("area2 < 0 || area2 >= Wolf.NUMAREAS"); 118 | } 119 | level.state.areaconnect[area1][area2]++; 120 | level.state.areaconnect[area2][area1]++; 121 | } 122 | 123 | /** 124 | * @description Disconnect ares 125 | * @memberOf Wolf.Areas 126 | * @param {object} level The level object 127 | * @param {number} area1 Area 1 128 | * @param {number} area2 Area 2 129 | */ 130 | function disconnect(level, area1, area2) { 131 | if (area1 < 0 || area1 >= Wolf.NUMAREAS) { 132 | throw new Error("area1 < 0 || area1 >= Wolf.NUMAREAS"); 133 | } 134 | if (area2 < 0 || area2 >= Wolf.NUMAREAS) { 135 | throw new Error("area2 < 0 || area2 >= Wolf.NUMAREAS"); 136 | } 137 | level.state.areaconnect[area1][area2]--; 138 | level.state.areaconnect[area2][area1]--; 139 | } 140 | 141 | return { 142 | init : init, 143 | connect : connect, 144 | join : join, 145 | disconnect : disconnect 146 | }; 147 | 148 | })(); 149 | 150 | -------------------------------------------------------------------------------- /js/doors.js: -------------------------------------------------------------------------------- 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 . 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 | 28 | /** 29 | * @namespace 30 | * @description Door management 31 | */ 32 | Wolf.Doors = (function() { 33 | 34 | Wolf.setConsts({ 35 | CLOSEWALL : Wolf.MINDIST, // Space between wall & player 36 | MAXDOORS : 64, // max number of sliding doors 37 | 38 | MAX_DOORS : 256, // jseidelin: doesn't look like this is used? 39 | DOOR_TIMEOUT : 300, 40 | DOOR_MINOPEN : 50, 41 | DOOR_FULLOPEN : 63, 42 | DOOR_VERT : 255, 43 | DOOR_HORIZ : 254, 44 | DOOR_E_VERT : 253, 45 | DOOR_E_HORIZ : 252, 46 | DOOR_G_VERT : 251, 47 | DOOR_G_HORIZ : 250, 48 | DOOR_S_VERT : 249, 49 | DOOR_S_HORIZ : 248, 50 | FIRST_DOOR : 248, 51 | LAST_LOCK : 251, 52 | 53 | TEX_DOOR : 98, 54 | // TEX_DOOR : 126, 55 | 56 | dr_closing : -1, 57 | dr_closed : 0, 58 | dr_opening : 1, 59 | dr_open : 2 60 | }); 61 | Wolf.setConsts({ 62 | // texture IDs used by cache routines 63 | TEX_DDOOR : (0 + Wolf.TEX_DOOR), // Simple Door 64 | TEX_PLATE : (2 + Wolf.TEX_DOOR), // Door Plate 65 | TEX_DELEV : (4 + Wolf.TEX_DOOR), // Elevator Door 66 | TEX_DLOCK : (6 + Wolf.TEX_DOOR) // Locked Door 67 | }); 68 | 69 | 70 | /** 71 | * @description Reset doors in the level 72 | * @memberOf Wolf.Doors 73 | * @param {object} level The level object. 74 | */ 75 | function reset(level) { 76 | level.state.numDoors = 0; 77 | 78 | for (var x=0;x<64;x++) { 79 | level.state.doorMap[x] = []; 80 | for (var y=0;y<64;y++) { 81 | level.state.doorMap[x][y] = 0; 82 | } 83 | } 84 | } 85 | 86 | /** 87 | * @description Spawn a door at the specified position. 88 | * @memberOf Wolf.Doors 89 | * @param {object} level The level object. 90 | * @param {number} x The x coordinate. 91 | * @param {number} y The y coordinate. 92 | * @param {number} type The door type. 93 | * @returns {number} The index of the new door. 94 | */ 95 | function spawn(level, x, y, type) { 96 | if (level.state.numDoors >= Wolf.MAXDOORS) { 97 | throw new Error("Too many Doors on level!"); 98 | } 99 | var door = level.state.doorMap[x][y] = { 100 | type : -1, 101 | vertical : 0, 102 | texture : -1, 103 | ticcount : 0 104 | }; 105 | 106 | switch(type) { 107 | case 0x5A: 108 | door.type = Wolf.DOOR_VERT; 109 | door.vertical = true; 110 | door.texture = Wolf.TEX_DDOOR + 1; 111 | break; 112 | case 0x5B: 113 | door.type = Wolf.DOOR_HORIZ; 114 | door.vertical = false; 115 | door.texture = Wolf.TEX_DDOOR; 116 | break; 117 | case 0x5C: 118 | door.type = Wolf.DOOR_G_VERT; 119 | door.vertical = true; 120 | door.texture = Wolf.TEX_DLOCK; 121 | break; 122 | case 0x5D: 123 | door.type = Wolf.DOOR_G_HORIZ; 124 | door.vertical = false; 125 | door.texture = Wolf.TEX_DLOCK; 126 | break; 127 | case 0x5E: 128 | door.type = Wolf.DOOR_S_VERT; 129 | door.vertical = true; 130 | door.texture = Wolf.TEX_DLOCK + 1; 131 | break; 132 | case 0x5F: 133 | door.type = Wolf.DOOR_S_HORIZ; 134 | door.vertical = false; 135 | door.texture = Wolf.TEX_DLOCK + 1; 136 | break; 137 | case 0x64: 138 | door.type = Wolf.DOOR_E_VERT; 139 | door.vertical = true; 140 | door.texture = Wolf.TEX_DELEV + 1; 141 | break; 142 | case 0x65: 143 | door.type = Wolf.DOOR_E_HORIZ; 144 | door.vertical = false; 145 | door.texture = Wolf.TEX_DELEV; 146 | break; 147 | default: 148 | throw new Error("Unknown door type: " + type); 149 | } 150 | 151 | door.tile = { 152 | x : x, 153 | y : y 154 | }; 155 | door.action = Wolf.dr_closed; 156 | 157 | level.state.doors[level.state.numDoors] = door; 158 | level.state.numDoors++; 159 | 160 | return level.state.numDoors - 1; 161 | } 162 | 163 | /** 164 | * @description Check to see if a door is open. If there are no doors in tile assume a closed door! 165 | * @memberOf Wolf.Doors 166 | * @param {object} doors The door object. 167 | * @returns {number} DOOR_FULLOPEN if door is opened, 168 | 0 if door is closed, 169 | >0 = Wolf.DOOR_FULLOPEN) { // door fully opened! 200 | door.action = Wolf.dr_open; 201 | door.ticcount = 0; 202 | } else { // opening! 203 | if (door.ticcount == 0) { 204 | // door is just starting to open, so connect the areas 205 | Wolf.Areas.join(level, door.area1, door.area2); 206 | Wolf.Areas.connect(level, player.areanumber); 207 | 208 | if (level.state.areabyplayer[door.area1]) { // Door Opening sound! 209 | Wolf.Sound.startSound(player.position, doorPos, 1, Wolf.CHAN_AUTO, "sfx/010.wav", 1, Wolf.ATTN_STATIC, 0); 210 | } 211 | } 212 | 213 | door.ticcount += tics; 214 | 215 | if (door.ticcount > Wolf.DOOR_FULLOPEN) { 216 | door.ticcount = Wolf.DOOR_FULLOPEN; 217 | } 218 | } 219 | break; 220 | 221 | case Wolf.dr_closing: 222 | if (door.ticcount <= 0) { // door fully closed! disconnect areas! 223 | Wolf.Areas.disconnect(level, door.area1, door.area2); 224 | Wolf.Areas.connect(level, player.areanumber); 225 | door.ticcount = 0; 226 | door.action = Wolf.dr_closed; 227 | } else { // closing! 228 | if (door.ticcount == Wolf.DOOR_FULLOPEN) { 229 | if (level.state.areabyplayer[door.area1]) { // Door Closing sound! 230 | Wolf.Sound.startSound(player.position, doorPos, 1, Wolf.CHAN_AUTO, "sfx/007.wav", 1, Wolf.ATTN_STATIC, 0); 231 | } 232 | } 233 | door.ticcount -= tics; 234 | if (door.ticcount < 0) { 235 | door.ticcount = 0; 236 | } 237 | } 238 | break; 239 | 240 | case Wolf.dr_open: 241 | if (door.ticcount > Wolf.DOOR_MINOPEN) { 242 | // If player or something is in door do not close it! 243 | if (!canCloseDoor(level, player, door.tile.x, door.tile.y, door.vertical)) { 244 | door.ticcount = Wolf.DOOR_MINOPEN; // do not close door immediately! 245 | } 246 | } 247 | if (door.ticcount >= Wolf.DOOR_TIMEOUT) { 248 | // Door timeout, time to close it! 249 | door.action = Wolf.dr_closing; 250 | door.ticcount = Wolf.DOOR_FULLOPEN; 251 | } else { 252 | // Increase timeout! 253 | door.ticcount += tics; 254 | } 255 | break; 256 | } // End switch lvldoors->Doors[ n ].action 257 | } // End for n = 0 ; n < lvldoors->numDoors ; ++n 258 | } 259 | 260 | /** 261 | * @description Set the areas doors in a level 262 | * @memberOf Wolf.Doors 263 | * @param {object} level The level object. 264 | * @param {array} areas The areas map. 265 | */ 266 | function setAreas(level) { 267 | var n, x, y, 268 | door; 269 | for (n=0; n= 0 ? level.areas[x + 1][y] : 0; 276 | door.area2 = level.areas[x - 1][y] >= 0 ? level.areas[x - 1][y] : 0; 277 | } else { 278 | door.area1 = level.areas[x][y + 1] >= 0 ? level.areas[x][y + 1] : 0; 279 | door.area2 = level.areas[x][y - 1] >= 0 ? level.areas[x][y - 1] : 0; 280 | } 281 | } 282 | } 283 | 284 | 285 | /** 286 | * @description Open a door 287 | * @memberOf Wolf.Doors 288 | * @param {object} doors The door object. 289 | */ 290 | function open(door) { 291 | if (door.action == Wolf.dr_open) { 292 | door.ticcount = 0; // reset opened time 293 | } else { 294 | door.action = Wolf.dr_opening; // start opening it 295 | } 296 | } 297 | 298 | /** 299 | * @description Change the state of a door 300 | * @private 301 | * @param {object} level The level object. 302 | * @param {object} player The player object. 303 | * @param {object} doors The door object. 304 | */ 305 | function changeDoorState(level, player, door) { 306 | if (door.action < Wolf.dr_opening ) { 307 | open(door); 308 | } else if (door.action == Wolf.dr_open && canCloseDoor(level, player, door.tile.x, door.tile.y, door.vertical)) { 309 | // !@# for the iphone with automatic using, don't allow any door close actions 310 | // Door->action = dr_closing; 311 | // Door->ticcount = DOOR_FULLOPEN; 312 | } 313 | } 314 | 315 | 316 | function canCloseDoor(level, player, x, y, vert ) { 317 | var n, 318 | tileX = Wolf.POS2TILE(player.position.x), 319 | tileY = Wolf.POS2TILE(player.position.y), 320 | guard; 321 | 322 | if (tileX == x && tileY == y ) { 323 | return false; 324 | } 325 | 326 | if (vert) { 327 | if (tileY == y) { 328 | if (Wolf.POS2TILE(player.position.x + Wolf.CLOSEWALL) == x) { 329 | return false; 330 | } 331 | if (Wolf.POS2TILE(player.position.x - Wolf.CLOSEWALL) == x) { 332 | return false; 333 | } 334 | } 335 | 336 | for (n = 0; n. 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 | 28 | /** 29 | * @namespace 30 | * @description Episode data 31 | */ 32 | Wolf.Episodes = [ 33 | { 34 | name : "Escape from Wolfenstein", 35 | enabled : true, 36 | levels : [ 37 | { file : "maps/w00.map", partime : 1.5 }, 38 | { file : "maps/w01.map", partime : 2.0 }, 39 | { file : "maps/w02.map", partime : 2.0 }, 40 | { file : "maps/w03.map", partime : 3.5 }, 41 | { file : "maps/w04.map", partime : 3.0 }, 42 | { file : "maps/w05.map", partime : 3.0 }, 43 | { file : "maps/w06.map", partime : 2.5 }, 44 | { file : "maps/w07.map", partime : 2.5 }, 45 | { file : "maps/w08.map", partime : 0.0 }, 46 | { file : "maps/w09.map", partime : 0.0, secret : true } 47 | ] 48 | },{ 49 | name : "Operation: Eisenfaust", 50 | enabled : true, 51 | levels : [ 52 | { file : "maps/w10.map", partime : 1.5 }, 53 | { file : "maps/w11.map", partime : 3.5 }, 54 | { file : "maps/w12.map", partime : 3.0 }, 55 | { file : "maps/w13.map", partime : 2.0 }, 56 | { file : "maps/w14.map", partime : 4.0 }, 57 | { file : "maps/w15.map", partime : 6.0 }, 58 | { file : "maps/w16.map", partime : 1.0 }, 59 | { file : "maps/w17.map", partime : 3.0 }, 60 | { file : "maps/w18.map", partime : 0.0 }, 61 | { file : "maps/w19.map", partime : 0.0, secret : true } 62 | ] 63 | },{ 64 | name : "Die, Fuhrer, Die!", 65 | enabled : true, 66 | levels : [ 67 | { file : "maps/w20.map", partime : 1.5 }, 68 | { file : "maps/w21.map", partime : 1.5 }, 69 | { file : "maps/w22.map", partime : 2.5 }, 70 | { file : "maps/w23.map", partime : 2.5 }, 71 | { file : "maps/w24.map", partime : 3.5 }, 72 | { file : "maps/w25.map", partime : 2.5 }, 73 | { file : "maps/w26.map", partime : 2.0 }, 74 | { file : "maps/w27.map", partime : 6.0 }, 75 | { file : "maps/w28.map", partime : 0.0 }, 76 | { file : "maps/w29.map", partime : 0.0, secret : true } 77 | ] 78 | } 79 | ]; 80 | 81 | -------------------------------------------------------------------------------- /js/file.js: -------------------------------------------------------------------------------- 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 . 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 | 28 | /** 29 | * @namespace 30 | * @description Binary file reading 31 | */ 32 | Wolf.File = (function() { 33 | 34 | 35 | /** 36 | * @description Open a file from URL 37 | * @memberOf Wolf.File 38 | * @param {string} url The URL to open 39 | * @param {function} callback Is called when file has been loaded. Second argument is file obj. 40 | */ 41 | function openURL(url, callback) { 42 | var xhr = new XMLHttpRequest(); 43 | 44 | xhr.onreadystatechange = function() { 45 | if (xhr.readyState == 4) { 46 | if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 0) { 47 | callback(null, { 48 | data : xhr.responseText, 49 | size : xhr.responseText.length, 50 | position : 0 51 | }); 52 | } else { 53 | callback(new Error("Server returned HTTP status: " + xhr.status)); 54 | } 55 | } 56 | } 57 | xhr.open("GET", url, true); 58 | xhr.overrideMimeType('text/plain; charset=x-user-defined'); 59 | xhr.send(null); 60 | } 61 | 62 | 63 | function atob(str) { 64 | str = str.replace(/=+$/, ""); 65 | var b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 66 | a, b, c, b1, b2, b3, b4, 67 | chr = String.fromCharCode, 68 | out = []; 69 | for (var i=0,len=str.length;i> 4) & 0x3); 76 | b = ((b2 & 0xF) << 4) | ((b3 >> 2) & 0xF); 77 | c = ((b3 & 0x3) << 6) | (b4 & 0x3F); 78 | 79 | out.push(chr(a), chr(b), chr(c)); 80 | } 81 | return out.join(""); 82 | } 83 | 84 | /** 85 | * @description Open a file from base64 filetable 86 | * @memberOf Wolf.File 87 | * @param {string} filename The name of the file to open 88 | * @param {object} files The filetable 89 | * @param {function} callback Is called when file has been loaded. Second argument is file obj. 90 | */ 91 | function open(filename, files, callback) { 92 | var b64data = files[filename]; 93 | if (b64data) { 94 | var data = atob(b64data); 95 | callback(null, { 96 | data : data, 97 | size : data.length, 98 | position : 0 99 | }); 100 | } else { 101 | callback(new Error("File not found: " + filename)); 102 | } 103 | } 104 | 105 | /** 106 | * @description Read an unsigned 8-bit integer from a file and advance the file position. 107 | * @memberOf Wolf.File 108 | * @param {object} f The file 109 | * @returns {number} 110 | */ 111 | function readUInt8(f) { 112 | var b = f.data.charCodeAt(f.position) & 0xFF 113 | f.position++; 114 | return b; 115 | } 116 | 117 | /** 118 | * @description Read a signed 8-bit integer from a file and advance the file position. 119 | * @memberOf Wolf.File 120 | * @param {object} f The file 121 | * @returns {number} 122 | */ 123 | function readInt8(f) { 124 | var v = readUInt8(f); 125 | return v > 127 ? v - 256 : v; 126 | } 127 | 128 | /** 129 | * @description Read an unsigned 16-bit integer from a file and advance the file position. 130 | * @memberOf Wolf.File 131 | * @param {object} f The file 132 | * @returns {number} 133 | */ 134 | function readUInt16(f) { 135 | var v = readUInt8(f) + (readUInt8(f) << 8); 136 | return (v < 0) ? v + 0x10000 : v; 137 | } 138 | 139 | /** 140 | * @description Read a signed 16-bit integer from a file and advance the file position. 141 | * @memberOf Wolf.File 142 | * @param {object} f The file 143 | * @returns {number} 144 | */ 145 | function readInt16(f) { 146 | var v = readUInt16(f); 147 | return (v > 0x7fff) ? v - 0x10000 : v; 148 | } 149 | 150 | /** 151 | * @description Read an unsigned 32-bit integer from a file and advance the file position. 152 | * @memberOf Wolf.File 153 | * @param {object} f The file 154 | * @returns {number} 155 | */ 156 | function readUInt32(f) { 157 | var b0 = readUInt8(f), 158 | b1 = readUInt8(f), 159 | b2 = readUInt8(f), 160 | b3 = readUInt8(f), 161 | v = ((((b3 << 8) + b2) << 8) + b1 << 8) + b0; 162 | return (v < 0) ? v + 0x100000000 : v; 163 | } 164 | 165 | /** 166 | * @description Read a signed 32-bit int from a file and advance the file position. 167 | * @memberOf Wolf.File 168 | * @param {object} f The file 169 | * @returns {number} 170 | */ 171 | function readInt32(f) { 172 | var v = readUInt32(f); 173 | return (v > 0x7fffffff) ? v - 0x100000000 : v; 174 | } 175 | 176 | /** 177 | * @description Read a string from a file and advance the file position. 178 | * @memberOf Wolf.File 179 | * @param {object} f The file 180 | * @param {number} length The length of the string 181 | * @returns {string} 182 | */ 183 | function readString(f, length) { 184 | var str = f.data.substr(f.position, length); 185 | f.position += length; 186 | return str; 187 | } 188 | 189 | /** 190 | * @description Read an array of bytes a file and advance the file position. 191 | * @memberOf Wolf.File 192 | * @param {object} f The file 193 | * @param {number} num The number of bytes to read 194 | * @returns {array} 195 | */ 196 | function readBytes(f, num) { 197 | var b = []; 198 | for (var i=0;i. 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 | 28 | /** 29 | * @namespace 30 | * @description Functions for capturing keyboard/mouse input 31 | */ 32 | Wolf.Input = (function() { 33 | 34 | var keys, 35 | lmbDown = false, 36 | rmbDown = false, 37 | bindings = [], 38 | hasFocus = false, 39 | mouseX = -1, mouseY = -1, 40 | mouseMoveX = 0, mouseMoveY = 0; 41 | 42 | function init() { 43 | var game = $("#game"), 44 | main = $("#main"), 45 | renderer = $("#game .renderer"); 46 | 47 | if (!keys) { 48 | keys = []; 49 | 50 | $(document) 51 | .on("keydown", function(e) { 52 | e.preventDefault(); 53 | 54 | if (!Wolf.Game.isPlaying()) { 55 | return; 56 | } 57 | 58 | keys[e.keyCode] = true; 59 | if (bindings[e.keyCode]) { 60 | for (var i=0,n=bindings[e.keyCode].length;i 1 || mouseY < 0 || mouseY > 1) { 210 | return null; 211 | } else { 212 | return { 213 | x : (mouseX - 0.5) * 2, 214 | y : (mouseY - 0.5) * 2 215 | }; 216 | } 217 | } 218 | 219 | function getMouseMovement() { 220 | var x = mouseMoveX, 221 | y = mouseMoveY; 222 | mouseMoveX = 0; 223 | mouseMoveY = 0; 224 | return { 225 | x : x / screen.width, 226 | y : y / screen.height 227 | }; 228 | } 229 | 230 | function getPointer() { 231 | var pointer = navigator.pointer || 232 | navigator.webkitPointer || 233 | navigator.mozPointer || 234 | navigator.msPointer || 235 | navigator.oPointer; 236 | return pointer; 237 | } 238 | 239 | function isPointerLocked() { 240 | var pointer = getPointer(); 241 | return pointer && pointer.isLocked && pointer.isLocked(); 242 | } 243 | 244 | function lockPointer() { 245 | var pointer = getPointer(); 246 | if (!pointer) { 247 | return; 248 | } 249 | 250 | if (Wolf.Game.isFullscreen()) { 251 | pointer.lock($("#game")[0], 252 | function(e) { 253 | Wolf.log("Pointer locked") 254 | }, function(e) { 255 | Wolf.log("Could not lock pointer: " + e); 256 | } 257 | ); 258 | } 259 | } 260 | 261 | function unlockPointer() { 262 | var pointer = getPointer(); 263 | if (!pointer) { 264 | return; 265 | } 266 | pointer.unlock($("#game")[0]); 267 | } 268 | 269 | 270 | return { 271 | init : init, 272 | reset : reset, 273 | resetMouse : resetMouse, 274 | checkKeys : checkKeys, 275 | clearKeys : clearKeys, 276 | bindKey : bindKey, 277 | leftMouseDown : leftMouseDown, 278 | rightMouseDown : rightMouseDown, 279 | getMouseCoords : getMouseCoords, 280 | getMouseMovement : getMouseMovement, 281 | isPointerLocked : isPointerLocked, 282 | lockPointer : lockPointer, 283 | unlockPointer : unlockPointer 284 | }; 285 | 286 | })(); 287 | 288 | 289 | Wolf.Keys = { 290 | LEFT : 37, 291 | UP : 38, 292 | RIGHT : 39, 293 | DOWN : 40, 294 | ENTER : 13, 295 | SPACE : 32, 296 | SHIFT : 16, 297 | CTRL : 17, 298 | ALT : 18, 299 | ESC : 27, 300 | HOME : 36, 301 | END : 35, 302 | DEL : 46, 303 | INS : 45, 304 | PGUP : 33, 305 | PGDN : 34, 306 | SLASH : 111, 307 | MINUS : 109, 308 | PLUS : 107, 309 | COMMA : 188, 310 | PERIOD : 190, 311 | 1 : 49, 312 | 2 : 50, 313 | 3 : 51, 314 | 4 : 52, 315 | 5 : 53, 316 | 6 : 54, 317 | 7 : 55, 318 | 8 : 56, 319 | 9 : 57, 320 | 0 : 58, 321 | A : 65, 322 | B : 66, 323 | C : 67, 324 | D : 68, 325 | E : 69, 326 | F : 70, 327 | G : 71, 328 | H : 72, 329 | I : 73, 330 | J : 74, 331 | K : 75, 332 | L : 76, 333 | M : 77, 334 | N : 78, 335 | O : 79, 336 | P : 80, 337 | Q : 81, 338 | R : 82, 339 | S : 83, 340 | T : 84, 341 | U : 85, 342 | V : 86, 343 | W : 87, 344 | X : 88, 345 | Y : 89, 346 | Z : 90, 347 | F1 : 112, 348 | F2 : 113, 349 | F3 : 114, 350 | F4 : 115, 351 | F5 : 116, 352 | F6 : 117, 353 | F7 : 118, 354 | F8 : 119, 355 | F9 : 120, 356 | F10 : 121, 357 | F11 : 122, 358 | F12 : 123 359 | }; -------------------------------------------------------------------------------- /js/load.js: -------------------------------------------------------------------------------- 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 . 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 | 28 | (function($) { 29 | 30 | // these files are preloaded while the title screen is showing 31 | var files = [ 32 | "js/requestanimframe.js", 33 | 34 | "js/wolf.js", 35 | "js/random.js", 36 | "js/angle.js", 37 | "js/math.js", 38 | "js/input.js", 39 | "js/sound.js", 40 | "js/menu.js", 41 | "js/file.js", 42 | "js/game.js", 43 | "js/player.js", 44 | "js/sprites.js", 45 | "js/powerups.js", 46 | "js/ai.js", 47 | "js/actorai.js", 48 | "js/actors.js", 49 | "js/actstat.js", 50 | "js/weapon.js", 51 | "js/doors.js", 52 | "js/pushwall.js", 53 | "js/areas.js", 54 | "js/level.js", 55 | "js/raycaster.js", 56 | "js/renderer.js", 57 | 58 | "js/episodes.js", 59 | "js/maps.js", 60 | 61 | "preload!art/menubg_main.png", 62 | "preload!art/menuitems.png", 63 | "preload!art/menuselector.png" 64 | 65 | ]; 66 | 67 | // these files are preloaded in the background after the menu is displayed. 68 | // only non-essential files here 69 | var files2 = [ 70 | "preload!art/menubg_episodes.png", 71 | "preload!art/menuitems_episodes.png", 72 | "preload!art/menubg_skill.png", 73 | "preload!art/menubg_levels.png", 74 | "preload!art/menuitems_levels.png", 75 | "preload!art/skillfaces.png", 76 | "preload!art/getpsyched.png", 77 | "preload!art/menubg_control.png", 78 | "preload!art/menulight.png", 79 | "preload!art/menubg_customize.png", 80 | "preload!art/control_keys.png", 81 | "preload!art/confirm_newgame.png", 82 | "preload!art/paused.png" 83 | ]; 84 | 85 | $(document).ready(function() { 86 | 87 | var progress = $("
"), 88 | n = 0; 89 | 90 | progress.addClass("load-progress").appendTo("#title-screen"); 91 | $("#title-screen").show(); 92 | 93 | 94 | yepnope.addPrefix("preload", function(resource) { 95 | resource.noexec = true; 96 | resource.instead = function(input, callback) { 97 | var image = new Image(); 98 | image.onload = callback; 99 | image.onerror = callback; 100 | image.src = input.substr(input.lastIndexOf("!")+1); 101 | }; 102 | return resource; 103 | }); 104 | 105 | 106 | Modernizr.load([ 107 | { 108 | load : files, 109 | callback : function(file) { 110 | progress.width((++n / files.length) * 100 + "%"); 111 | }, 112 | complete : function() { 113 | progress.remove(); 114 | $("#title-screen").fadeOut(1500, function() { 115 | Wolf.Input.init(); 116 | Wolf.Game.init(); 117 | Wolf.Menu.show(); 118 | }); 119 | // preload non-essential art 120 | Modernizr.load(files2); 121 | } 122 | } 123 | ]); 124 | }); 125 | 126 | })(jQuery); -------------------------------------------------------------------------------- /js/maps.sample.js: -------------------------------------------------------------------------------- 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 . 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 | /** 28 | * @description Encoded map file data (Example) 29 | * 30 | * This file is a table of base64 encoded map data. 31 | * Note: No actual data is included in this release. 32 | */ 33 | 34 | Wolf.MapData = { 35 | "maps/w00.map" : "... base64 encoded map file data here ...", 36 | "maps/w01.map" : "... base64 encoded map file data here ..." 37 | }; 38 | -------------------------------------------------------------------------------- /js/math.js: -------------------------------------------------------------------------------- 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 . 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 | /** 28 | * @namespace 29 | * @description Math functions and lookup tables 30 | */ 31 | Wolf.Math = (function() { 32 | 33 | // ------------------------- * LUTs * ------------------------- 34 | var SinTable = [], // [ ANG_360 + ANG_90 + 1 ], 35 | CosTable = [], // SinTable + ANG_90, 36 | TanTable = [], //[ ANG_360 + 1 ]; 37 | 38 | XnextTable = [], //[ ANG_360 + 1 ], 39 | YnextTable = [], //[ ANG_360 + 1 ], 40 | 41 | ColumnAngle = [], // [ 640 ]; // ViewAngle=PlayerAngle+ColumnAngle[curcolumn]; /in fines/ 42 | 43 | // Angle Direction Types & LUTs (Hard Coded! Please do not mess them) 44 | q_first = 0, q_second = 1, q_third = 2, q_fourth = 3, // quadrant; 45 | dir4_east = 0, dir4_north = 1, dir4_west = 2, dir4_south = 3, dir4_nodir = 4, // dir4type; 46 | 47 | dir8_east = 0, dir8_northeast = 1, dir8_north = 2, dir8_northwest = 3, dir8_west = 4, 48 | dir8_southwest = 5, dir8_south = 6, dir8_southeast = 7, dir8_nodir = 8, // dir8type; 49 | 50 | dx4dir = [1, 0, -1, 0, 0], // dx & dy based on direction 51 | dy4dir = [0, 1, 0, -1, 0], 52 | dx8dir = [1, 1, 0, -1, -1, -1, 0, 1, 0], // dx & dy based on direction 53 | dy8dir = [0, 1, 1, 1, 0, -1, -1, -1, 0], 54 | opposite4 = [2, 3, 0, 1, 4], 55 | opposite8 = [4, 5, 6, 7, 0, 1, 2, 3, 8], 56 | dir4to8 = [0, 2, 4, 6, 8], 57 | diagonal = [ 58 | /* east */ [dir8_nodir, dir8_nodir, dir8_northeast, dir8_nodir, dir8_nodir, dir8_nodir, dir8_southeast, dir8_nodir, dir8_nodir], 59 | [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], 60 | /* north */ [dir8_northeast, dir8_nodir, dir8_nodir, dir8_nodir, dir8_northwest, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], 61 | [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], 62 | /* west */ [dir8_nodir, dir8_nodir, dir8_northwest, dir8_nodir, dir8_nodir, dir8_nodir, dir8_southwest, dir8_nodir, dir8_nodir], 63 | [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], 64 | /* south */ [dir8_southeast, dir8_nodir, dir8_nodir, dir8_nodir, dir8_southwest, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], 65 | [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], 66 | [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir] 67 | ], 68 | 69 | // dir of delta tooks dx{-1|0|1}+1 & dy{-1|0|1}+1 and give direction 70 | dir4d = [ 71 | [dir4_nodir, dir4_west , dir4_nodir], 72 | [dir4_south, dir4_nodir, dir4_north], 73 | [dir4_nodir, dir4_east , dir4_nodir] 74 | ], 75 | dir8angle = [Wolf.ANG_0, Wolf.ANG_45, Wolf.ANG_90, Wolf.ANG_135, Wolf.ANG_180, Wolf.ANG_225, Wolf.ANG_270, Wolf.ANG_315, Wolf.ANG_0]; 76 | dir4angle = [Wolf.ANG_0, Wolf.ANG_90, Wolf.ANG_180, Wolf.ANG_270, Wolf.ANG_0]; 77 | 78 | 79 | /** 80 | * @private 81 | * @description Build LUTs, etc. 82 | */ 83 | function buildTables() { 84 | var angle, tanfov2, tanval, value, 85 | n; 86 | 87 | for (n = 0; n <= Wolf.ANG_90 ; ++n) { 88 | angle = Wolf.FINE2RAD(n); 89 | value = Math.sin(angle); 90 | SinTable[n] = SinTable[Wolf.ANG_180 - n] = SinTable[n + Wolf.ANG_360] = value; 91 | SinTable[Wolf.ANG_180 + n] = SinTable[Wolf.ANG_360 - n] = -value; 92 | } 93 | 94 | for (n = 0; n <= SinTable.length - Wolf.ANG_90; ++n) { 95 | CosTable[n] = SinTable[n + Wolf.ANG_90]; 96 | } 97 | 98 | for (n = 0; n <= Wolf.ANG_360 ; ++n) { 99 | angle = Wolf.FINE2RAD(n); //angle is in radians, n is in FINEs 100 | 101 | if (n == Wolf.ANG_90 || n == Wolf.ANG_270) { 102 | TanTable[n] = Math.tan(Wolf.FINE2RAD(n - 0.5)); // infinity 103 | YnextTable[n] = (Wolf.FLOATTILE * Math.tan(Wolf.FINE2RAD(n - 0.5)))>>0; // infinity 104 | } else { 105 | TanTable[n] = Math.tan(angle); 106 | YnextTable[n] = (Wolf.FLOATTILE * Math.tan(angle))>>0; 107 | } 108 | 109 | if(n == Wolf.ANG_0 || n == Wolf.ANG_360) { 110 | XnextTable[n] = (Wolf.FLOATTILE / Math.tan(Wolf.FINE2RAD(n + 0.5)))>>0; // infinity 111 | } else if (n == Wolf.ANG_180) { 112 | XnextTable[n] = (Wolf.FLOATTILE / Math.tan(Wolf.FINE2RAD(n - 0.5)))>>0; // -infinity 113 | } else if (n == Wolf.ANG_90 || n == Wolf.ANG_270) { 114 | XnextTable[n] = 0; 115 | } else { 116 | XnextTable[n] = (Wolf.FLOATTILE / Math.tan(angle))>>0; 117 | } 118 | } 119 | 120 | tanfov2 = (Math.tan(Wolf.DEG2RAD((calcFov(75, Wolf.XRES, Wolf.YRES) / 2.0)))) * (Wolf.XRES / Wolf.YRES); 121 | for (n = 0; n < Wolf.XRES; ++n) { 122 | tanval = tanfov2 * (-1.0 + 2.0 * n / (Wolf.XRES-1)); 123 | ColumnAngle[n] = Wolf.RAD2FINE(Math.atan(tanval)) >> 0; 124 | } 125 | 126 | Wolf.Random.init(1); // random number generators 127 | 128 | return 1; 129 | } 130 | 131 | 132 | /** 133 | * @description Calculate the field of view. 134 | * @memberOf Wolf.Math 135 | * @param {number} fovX Must be within 1 and 179 degrees. 136 | * @param {number} width Width of viewing area. 137 | * @param {number} height Height of viewing area. 138 | * @returns {number} The field of view in degrees. 139 | */ 140 | 141 | function calcFov(fovX, width, height) { 142 | if (fovX < 1 || fovX > 179) { 143 | throw Error("Bad fov: " + fovX ); 144 | } 145 | 146 | return Wolf.RAD2DEG(Math.atan(height / (width / Math.tan(fovX / 360 * Math.PI)))) * 2; 147 | } 148 | 149 | 150 | /** 151 | * @description Clips angle to [0..360] bounds. 152 | * @memberOf Wolf.Math 153 | * @param {number} alpha Angle in degrees. 154 | * @returns {number} Normalized angle. 155 | */ 156 | function normalizeAngle(alpha) { 157 | if (alpha > Wolf.ANG_360) { 158 | alpha %= Wolf.ANG_360; 159 | } 160 | if (alpha < Wolf.ANG_0) { 161 | alpha = Wolf.ANG_360 - (-alpha) % Wolf.ANG_360; 162 | } 163 | return alpha; 164 | } 165 | 166 | 167 | /** 168 | * @description Get quadrant. 169 | * @memberOf Wolf.Math 170 | * @param {number} angle Radian angle. 171 | * @returns {number} 172 | */ 173 | function getQuadrant(angle) { 174 | angle = Wolf.Angle.normalize(angle); 175 | 176 | if (angle < Math.PI / 2) { 177 | return q_first; 178 | } else if (angle < Math.PI) { 179 | return q_second; 180 | } else if (angle < 3 * Math.PI / 2) { 181 | return q_third; 182 | } else { 183 | return q_fourth; 184 | } 185 | } 186 | 187 | /** 188 | * @description Get 4 point direction. 189 | * @memberOf Wolf.Math 190 | * @param {number} angle Radian angle. 191 | * @returns {number} Directional point. 192 | */ 193 | function get4dir(angle) { 194 | angle = Wolf.Angle.normalize(angle + Math.PI / 4); 195 | 196 | if (angle < Math.PI / 2) { 197 | return dir4_east; 198 | } else if( angle < Math.PI ) { 199 | return dir4_north; 200 | } else if( angle < 3 * Math.PI / 2 ) { 201 | return dir4_west; 202 | } else { 203 | return dir4_south; 204 | } 205 | } 206 | 207 | /** 208 | * @description Get 8 point direction. 209 | * @memberOf Wolf.Math 210 | * @param {number} angle Radian angle. 211 | * @returns {number} Directional point. 212 | */ 213 | function get8dir(angle) { 214 | angle = Wolf.Angle.normalize(angle + Math.PI / 12); 215 | 216 | if ( angle <= (Math.PI / 4)) { 217 | return dir8_east; 218 | } else if (angle < (Math.PI / 2)) { 219 | return dir8_northeast; 220 | } else if (angle <= (3 * Math.PI / 4)) { 221 | return dir8_north; 222 | } else if (angle < Math.PI) { 223 | return dir8_northwest; 224 | } else if (angle <= (5 * Math.PI / 4)) { 225 | return dir8_west; 226 | } else if (angle < (3 * Math.PI / 2)) { 227 | return dir8_southwest; 228 | } else if (angle <= (7 * Math.PI / 4)) { 229 | return dir8_south; 230 | } else { 231 | return dir8_southeast; 232 | } 233 | } 234 | 235 | /** 236 | * @description calculates distance between a point (x, y) and a line. 237 | * @memberOf Wolf.Math 238 | * @param {number} x X coord of point 239 | * @param {number} y Y coord of point 240 | * @param {number} a Line angle in degrees 241 | * @returns {number} Distance 242 | */ 243 | function point2LineDist(x, y, a) { 244 | return Math.abs( (x * SinTable[a] - y * CosTable[a]) >> 0); 245 | } 246 | 247 | 248 | 249 | /** 250 | * @description Calculates line length to the point nearest to (poin). 251 | * @memberOf Wolf.Math 252 | * @param {number} x X coord of point 253 | * @param {number} y Y coord of point 254 | * @param {number} a Line angle in degrees 255 | * @returns {number} Distance 256 | */ 257 | function lineLen2Point( x, y, a) { 258 | return (x * CosTable[a] + y * SinTable[a]) >> 0; 259 | } 260 | 261 | 262 | /* 263 | point2 = {x,y} 264 | / | 265 | / | 266 | / | 267 | /a______|----------> x 268 | point1 = {x, y} 269 | */ 270 | /** 271 | * @description Returns angle in radians 272 | * @memberOf Wolf.Math 273 | * @param {number} x X coord of point 274 | * @param {number} y Y coord of point 275 | * @param {number} a Line angle in degrees 276 | * @returns {number} Distance 277 | */ 278 | function transformPoint(point1X, point1Y, point2X, point2Y) { 279 | var angle = Math.atan2(point1Y - point2Y, point1X - point2X); 280 | return Wolf.Angle.normalize(angle); 281 | } 282 | 283 | 284 | buildTables(); 285 | 286 | return { 287 | calcFov : calcFov, 288 | normalizeAngle : normalizeAngle, 289 | getQuadrant : getQuadrant, 290 | get4dir : get4dir, 291 | get8dir : get8dir, 292 | point2LineDist : point2LineDist, 293 | lineLen2Point : lineLen2Point, 294 | transformPoint : transformPoint, 295 | 296 | SinTable : SinTable, 297 | CosTable : CosTable, 298 | TanTable : TanTable, 299 | XnextTable : XnextTable, 300 | YnextTable : YnextTable, 301 | ColumnAngle : ColumnAngle, 302 | 303 | dir4_east : dir4_east, 304 | dir4_north : dir4_north, 305 | dir4_west : dir4_west, 306 | dir4_south : dir4_south, 307 | dir4_nodir : dir4_nodir, 308 | dir8_east : dir8_east, 309 | dir8_northeast : dir8_northeast, 310 | dir8_north : dir8_north, 311 | dir8_northwest : dir8_northwest, 312 | dir8_west : dir8_west, 313 | dir8_southwest : dir8_southwest, 314 | dir8_south : dir8_south, 315 | dir8_southeast : dir8_southeast, 316 | dir8_nodir : dir8_nodir, 317 | dx4dir : dx4dir, 318 | dy4dir : dy4dir, 319 | dx8dir : dx8dir, 320 | dy8dir : dy8dir, 321 | dir4angle : dir4angle, 322 | dir8angle : dir8angle, 323 | dir4to8 : dir4to8, 324 | opposite4 : opposite4, 325 | opposite8 : opposite8, 326 | diagonal : diagonal 327 | }; 328 | 329 | })(); -------------------------------------------------------------------------------- /js/menu.js: -------------------------------------------------------------------------------- 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 . 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 | /** 28 | * @namespace 29 | * @description Game menu management 30 | */ 31 | Wolf.Menu = (function() { 32 | var setupDone = false, 33 | menuInputActive = false, 34 | activeIndex = 0, 35 | activeMouseItem = null, 36 | activeEpisode, 37 | messageBlink, 38 | activeMessage, 39 | activeSkill; 40 | 41 | var keySprites = {}, 42 | i, 43 | keySpriteNames = [ 44 | "BLANK", 45 | "QUESTION", 46 | "SHIFT", 47 | "SPACE", 48 | "CTRL", 49 | "LEFT", 50 | "RIGHT", 51 | "UP", 52 | "DOWN", 53 | "ENTER", 54 | "DEL", 55 | "PGUP", 56 | "PGDN", 57 | "INS", 58 | "SLASH", 59 | "HOME", 60 | "COMMA", 61 | "PERIOD", 62 | "PLUS", 63 | "MINUS", 64 | "0", 65 | "1", 66 | "2", 67 | "3", 68 | "4", 69 | "5", 70 | "6", 71 | "7", 72 | "8", 73 | "9", 74 | "A", 75 | "B", 76 | "C", 77 | "D", 78 | "E", 79 | "F", 80 | "G", 81 | "H", 82 | "I", 83 | "J", 84 | "K", 85 | "L", 86 | "M", 87 | "N", 88 | "O", 89 | "P", 90 | "Q", 91 | "R", 92 | "S", 93 | "T", 94 | "U", 95 | "V", 96 | "W", 97 | "X", 98 | "Y", 99 | "Z" 100 | ]; 101 | 102 | for (i=0;i. 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 | 28 | Wolf.Powerups = (function() { 29 | 30 | Wolf.setConsts({ 31 | pow_gibs : 0, // 1% if <=10%; SLURPIESND 32 | pow_gibs2 : 1, // 1% if <=10%; SLURPIESND 33 | pow_alpo : 2, // 4% if <100%; HEALTH1SND 34 | pow_firstaid : 3, // 25% if <100%; HEALTH2SND 35 | pow_key1 : 4, // gold key; GETKEYSND 36 | pow_key2 : 5, // silver key; GETKEYSND 37 | pow_key3 : 6, // not used 38 | pow_key4 : 7, // not used 39 | pow_cross : 8, // 100pts; BONUS1SND 40 | pow_chalice : 9, // 500pts; BONUS2SND 41 | pow_bible : 10, // 1000pts; BONUS3SND 42 | pow_crown : 11, // 5000pts; BONUS4SND 43 | pow_clip : 12, // 8bul if <99bul; GETAMMOSND 44 | pow_clip2 : 13, // 4bul if <99bul; GETAMMOSND 45 | pow_machinegun : 14, // machine gun; GETMACHINESND 46 | pow_chaingun : 15, // gatling gun; GETGATLINGSND 47 | pow_food : 16, // 10% if <100%; HEALTH1SND 48 | pow_fullheal : 17, // 99%, 25bul; BONUS1UPSND 49 | pow_25clip : 18, // 25bul if <99bul; GETAMMOBOXSND 50 | pow_spear : 19, // spear of destiny! 51 | pow_last : 20 52 | // add new types here (after last) 53 | }); 54 | 55 | var texture = [ 56 | Wolf.SPR_STAT_34, // pow_gibs 57 | Wolf.SPR_STAT_38, // pow_gibs2 58 | Wolf.SPR_STAT_6, // pow_alpo 59 | Wolf.SPR_STAT_25, // pow_firstaid 60 | Wolf.SPR_STAT_20, // pow_key1 61 | Wolf.SPR_STAT_21, // pow_key2 62 | // not used 63 | Wolf.SPR_STAT_20, // pow_key3 64 | Wolf.SPR_STAT_20, // pow_key4 65 | 66 | Wolf.SPR_STAT_29, // pow_cross 67 | Wolf.SPR_STAT_30, // pow_chalice 68 | Wolf.SPR_STAT_31, // pow_bible 69 | Wolf.SPR_STAT_32, // pow_crown 70 | Wolf.SPR_STAT_26, // pow_clip 71 | Wolf.SPR_STAT_26, // pow_clip2 72 | Wolf.SPR_STAT_27, // pow_machinegun 73 | Wolf.SPR_STAT_28, // pow_chaingun 74 | Wolf.SPR_STAT_24, // pow_food 75 | Wolf.SPR_STAT_33, // pow_fullheal 76 | // spear 77 | Wolf.SPR_STAT_49, // pow_25clip 78 | Wolf.SPR_STAT_51 // pow_spear 79 | ]; 80 | 81 | 82 | function remove(level, powerup) { 83 | powerup.x = -1; 84 | powerup.y = -1; 85 | } 86 | 87 | function addNew(level) { 88 | /* 89 | for (var i = 0;i < level.state.numPowerups; i++ ) { 90 | if (level.state.powerups[i].x == -1 ) { 91 | return level.state.powerups[i]; 92 | } 93 | } 94 | */ 95 | /* 96 | if (level.state.numPowerups == Wolf.MAX_POWERUPS ) { 97 | return level.state.powerups[0]; 98 | } 99 | */ 100 | level.state.numPowerups++; 101 | 102 | var newp = { 103 | x : -1, 104 | y : -1, 105 | type : 0, 106 | sprite : null 107 | }; 108 | 109 | level.state.powerups[level.state.numPowerups-1] = newp; 110 | 111 | return newp; 112 | } 113 | 114 | function reset(level) { 115 | level.state.numPowerups = 0; 116 | level.state.powerups = []; 117 | } 118 | 119 | // x,y are in TILES. 120 | function spawn(level, x, y, type) { 121 | var newp = addNew(level); 122 | 123 | newp.sprite = Wolf.Sprites.getNewSprite(level); 124 | newp.type = type; 125 | 126 | Wolf.Sprites.setPos(level, newp.sprite, Wolf.TILE2POS(newp.x = x), Wolf.TILE2POS(newp.y = y), 0); 127 | 128 | Wolf.Sprites.setTex(level, newp.sprite, -1, texture[type]); 129 | 130 | level.tileMap[x][y] |= Wolf.POWERUP_TILE; 131 | // good place to update total treasure count! 132 | } 133 | 134 | 135 | function give(level, player, type) { 136 | var keynames = ["Gold", "Silver", "?", "?"]; 137 | 138 | switch (type) { 139 | // Keys 140 | case Wolf.pow_key1: 141 | case Wolf.pow_key2: 142 | case Wolf.pow_key3: 143 | case Wolf.pow_key4: 144 | type -= Wolf.pow_key1; 145 | Wolf.Player.giveKey(player, type); 146 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/012.wav", 1, Wolf.ATTN_NORM, 0); 147 | Wolf.Game.notify(keynames[type] + " key"); 148 | break; 149 | // Treasure 150 | case Wolf.pow_cross: 151 | Wolf.Player.givePoints(player, 100); 152 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/035.wav", 1, Wolf.ATTN_NORM, 0); 153 | if ( ++level.state.foundTreasure == level.state.totalTreasure ) { 154 | Wolf.Game.notify("You found the last treasure!"); 155 | } 156 | break; 157 | 158 | case Wolf.pow_chalice: 159 | Wolf.Player.givePoints(player, 500); 160 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/036.wav", 1, Wolf.ATTN_NORM, 0); 161 | if (++level.state.foundTreasure == level.state.totalTreasure) { 162 | Wolf.Game.notify("You found the last treasure!"); 163 | } 164 | break; 165 | 166 | case Wolf.pow_bible: 167 | Wolf.Player.givePoints(player, 1000); 168 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/037.wav", 1, Wolf.ATTN_NORM, 0); 169 | if (++level.state.foundTreasure == level.state.totalTreasure) { 170 | Wolf.Game.notify("You found the last treasure!"); 171 | } 172 | break; 173 | 174 | case Wolf.pow_crown: 175 | Wolf.Player.givePoints(player, 5000); 176 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/045.wav", 1, Wolf.ATTN_NORM, 0); 177 | if (++level.state.foundTreasure == level.state.totalTreasure) { 178 | Wolf.Game.notify("You found the last treasure!"); 179 | } 180 | break; 181 | 182 | // Health 183 | case Wolf.pow_gibs: 184 | if (!Wolf.Player.giveHealth(player, 1, 11)) { 185 | return false; 186 | } 187 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/061.wav", 1, Wolf.ATTN_NORM, 0); 188 | break; 189 | 190 | case Wolf.pow_alpo: 191 | if (!Wolf.Player.giveHealth(player, 4, 0)) { 192 | return false; 193 | } 194 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/033.wav", 1, Wolf.ATTN_NORM, 0); 195 | break; 196 | 197 | case Wolf.pow_food: 198 | if (!Wolf.Player.giveHealth(player, 10, 0)) { 199 | return false; 200 | } 201 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/033.wav", 1, Wolf.ATTN_NORM, 0); 202 | break; 203 | 204 | case Wolf.pow_firstaid: 205 | if (!Wolf.Player.giveHealth(player, 25, 0)) { 206 | return false; 207 | } 208 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/034.wav", 1, Wolf.ATTN_NORM, 0); 209 | break; 210 | 211 | // Weapon & Ammo 212 | case Wolf.pow_clip: 213 | if (!Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 8)) { 214 | return false; 215 | } 216 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/031.wav", 1, Wolf.ATTN_NORM, 0); 217 | break; 218 | 219 | case Wolf.pow_clip2: 220 | if (!Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 4)) { 221 | return false; 222 | } 223 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/031.wav", 1, Wolf.ATTN_NORM, 0); 224 | break; 225 | 226 | case Wolf.pow_25clip: 227 | if (!Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 25)) { 228 | return false; 229 | } 230 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/031.wav", 1, Wolf.ATTN_NORM, 0); 231 | break; 232 | 233 | case Wolf.pow_machinegun: 234 | Wolf.Player.giveWeapon(player, Wolf.WEAPON_AUTO ); 235 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/030.wav", 1, Wolf.ATTN_NORM, 0); 236 | Wolf.Game.notify("Machinegun"); 237 | break; 238 | 239 | case Wolf.pow_chaingun: 240 | Wolf.Player.giveWeapon(player, Wolf.WEAPON_CHAIN ); 241 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/038.wav", 1, Wolf.ATTN_NORM, 0); 242 | Wolf.Game.notify("Chaingun"); 243 | 244 | player.faceCount = -100; 245 | player.faceGotGun = true; 246 | break; 247 | 248 | // Artifacts 249 | case Wolf.pow_fullheal: 250 | // go to 150 health 251 | Wolf.Player.giveHealth(player, 99, 99 ); 252 | Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 25 ); 253 | Wolf.Player.giveLife(player); 254 | if (++level.state.foundTreasure == level.state.totalTreasure) { 255 | Wolf.Game.notify("You found the last treasure!"); 256 | } else { 257 | Wolf.Game.notify("Full Heal"); 258 | } 259 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/034.wav", 1, Wolf.ATTN_NORM, 0); 260 | Wolf.log("Extra life!"); 261 | break; 262 | 263 | default: 264 | Wolf.log("Warning: Unknown item type: " + type); 265 | break; 266 | } 267 | 268 | Wolf.Game.startBonusFlash(); 269 | 270 | return true; 271 | } 272 | 273 | // x,y are in TILES. 274 | function pickUp(level, player, x, y) { 275 | var i, pow, 276 | p_left = false, 277 | p_pick = false; 278 | 279 | for (i=0; i. 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 | /** 28 | * @namespace 29 | * @description Push wall management 30 | */ 31 | Wolf.PushWall = (function() { 32 | 33 | var PWall = {}; 34 | reset(); 35 | 36 | function reset() { 37 | PWall.active = false; 38 | PWall.tilesMoved = 0; 39 | PWall.pointsMoved = 0; 40 | PWall.dir = 0; 41 | PWall.x = 0; 42 | PWall.y = 0; 43 | PWall.dx = 0; 44 | PWall.dy = 0; 45 | PWall.texX = 0; 46 | PWall.texY = 0; 47 | } 48 | 49 | 50 | function push(level, x, y, dir) { 51 | var dx, dy; 52 | 53 | if (PWall.active) { 54 | return false; // another PWall is moving [only one at a time!] 55 | } 56 | 57 | dx = Wolf.Math.dx4dir[dir]; 58 | dy = Wolf.Math.dy4dir[dir]; 59 | 60 | if (level.tileMap[x + dx][y + dy] & (Wolf.SOLID_TILE | Wolf.DOOR_TILE)) { 61 | // noway (smth is blocking) 62 | return true; 63 | } 64 | 65 | // remove secret flag & make everything needed when pushwall used! 66 | level.tileMap[x][y] &= (~Wolf.SECRET_TILE); 67 | level.tileMap[x][y] &= (~Wolf.WALL_TILE); 68 | level.tileMap[x][y] |= Wolf.PUSHWALL_TILE; 69 | 70 | if (++level.state.foundSecrets == level.state.totalSecrets) { 71 | Wolf.Game.notify("You found the last secret!"); 72 | } else { 73 | Wolf.Game.notify("You found a secret!"); 74 | } 75 | 76 | Wolf.Sound.startSound(null, null, 1, Wolf.CHAN_AUTO, "sfx/034.wav", 1, Wolf.ATTN_STATIC, 0); 77 | 78 | // good way to avoid stuckness; [un]comment one more down! 79 | // it makes a tile behind pushwall unpassable 80 | level.tileMap[x + dx][y + dy] |= Wolf.PUSHWALL_TILE; 81 | level.wallTexX[x + dx][y + dy] = level.wallTexX[x][y]; 82 | level.wallTexY[x + dx][y + dy] = level.wallTexY[x][y]; 83 | 84 | // write down PWall info 85 | PWall.active = true; 86 | PWall.tilesMoved = PWall.pointsMoved = 0; 87 | PWall.dir = dir; 88 | PWall.x = x; 89 | PWall.y = y; 90 | PWall.dx = dx; 91 | PWall.dy = dy; 92 | PWall.texX = level.wallTexX[x][y]; 93 | PWall.texY = level.wallTexY[x][y]; 94 | 95 | return true; 96 | } 97 | 98 | 99 | function process(level, tics) { 100 | if (!PWall.active) { 101 | return; // no active PWall to work with 102 | } 103 | 104 | PWall.pointsMoved += tics; 105 | 106 | if (PWall.pointsMoved < 128) { 107 | return; 108 | } 109 | 110 | PWall.pointsMoved -= 128; 111 | PWall.tilesMoved++; 112 | // Free tile 113 | level.tileMap[PWall.x][PWall.y] &= (~Wolf.PUSHWALL_TILE); 114 | // Occupy new tile 115 | PWall.x += PWall.dx; 116 | PWall.y += PWall.dy; 117 | 118 | // Shall we move further? 119 | if (level.tileMap[PWall.x + PWall.dx][PWall.y + PWall.dy] & (Wolf.SOLID_TILE | Wolf.DOOR_TILE | Wolf.ACTOR_TILE | Wolf.POWERUP_TILE) || PWall.tilesMoved == 3) { 120 | level.tileMap[PWall.x][PWall.y] &= (~Wolf.PUSHWALL_TILE); // wall now 121 | level.tileMap[PWall.x][PWall.y] |= Wolf.WALL_TILE; // wall now 122 | level.wallTexX[PWall.x][PWall.y] = PWall.texX; 123 | level.wallTexY[PWall.x][PWall.y] = PWall.texY; 124 | PWall.active = false; // Free Push Wall 125 | } else { 126 | level.tileMap[PWall.x + PWall.dx][PWall.y + PWall.dy] |= Wolf.PUSHWALL_TILE; 127 | 128 | // Not sure if this is right but it fixed an issue with the pushwall texture changing mid-slide. 129 | level.wallTexX[PWall.x + PWall.dx][PWall.y + PWall.dy] = PWall.texX; 130 | level.wallTexY[PWall.x + PWall.dx][PWall.y + PWall.dy] = PWall.texY; 131 | } 132 | } 133 | 134 | function get() { 135 | return PWall; 136 | } 137 | 138 | return { 139 | reset : reset, 140 | process : process, 141 | push : push, 142 | get : get 143 | }; 144 | 145 | })(); 146 | -------------------------------------------------------------------------------- /js/random.js: -------------------------------------------------------------------------------- 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 . 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 | Wolf.Random = (function() { 28 | 29 | /* This is just John Carmack's table driven pseudo-random number generator */ 30 | var rndtable = [ 31 | 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 32 | 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, 33 | 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, 34 | 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, 35 | 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242, 36 | 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0, 37 | 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235, 38 | 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113, 39 | 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75, 40 | 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196, 41 | 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113, 42 | 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241, 43 | 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224, 44 | 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95, 45 | 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226, 46 | 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, 47 | 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 48 | 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136, 49 | 120, 163, 236, 249 50 | ]; 51 | 52 | var rndindex = 0; 53 | 54 | function init(randomize) { 55 | if (randomize ) { 56 | rndindex = (new Date).getTime() & 0xFF; 57 | } else { 58 | rndindex = 0; 59 | } 60 | } 61 | 62 | function rnd() { 63 | rndindex++; 64 | rndindex &= 0xFF; 65 | return rndtable[rndindex]; 66 | } 67 | 68 | 69 | return { 70 | init : init, 71 | rnd : rnd 72 | } 73 | 74 | })(); -------------------------------------------------------------------------------- /js/raycaster.js: -------------------------------------------------------------------------------- 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 . 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 | Wolf.setConsts({ 28 | UPPERZCOORD : 0.6, 29 | LOWERZCOORD : -0.6, 30 | 31 | // marks 32 | TRACE_MARK_MAP : 1, // marks traced area in 'AM_AutoMap.vis' array 33 | // obstacle levels 34 | TRACE_SIGHT : 2, // player sight 35 | TRACE_SIGHT_AI : 4, // enemy sight 36 | TRACE_BULLET : 8, // bullet 37 | TRACE_OBJECT : 16, // object 38 | 39 | TRACE_HIT_VERT : 32, // vertical wall was hit 40 | TRACE_HIT_DOOR : 64, // door was hit 41 | TRACE_HIT_PWALL : 128 // pushwall was hit 42 | }); 43 | 44 | Wolf.Raycaster = (function() { 45 | 46 | var x_tile_step = [ 1, -1, -1, 1 ], 47 | y_tile_step = [ 1, 1, -1, -1 ]; 48 | 49 | var TILESHIFT = Wolf.TILESHIFT, 50 | TRACE_HIT_VERT = Wolf.TRACE_HIT_VERT, 51 | TILEGLOBAL = Wolf.TILEGLOBAL, 52 | WALL_TILE = Wolf.WALL_TILE, 53 | DOOR_TILE = Wolf.DOOR_TILE, 54 | TILE2POS = Wolf.TILE2POS, 55 | POS2TILE = Wolf.POS2TILE, 56 | FINE2RAD = Wolf.FINE2RAD, 57 | TRACE_HIT_DOOR = Wolf.TRACE_HIT_DOOR, 58 | PUSHWALL_TILE = Wolf.PUSHWALL_TILE, 59 | TRACE_HIT_PWALL = Wolf.TRACE_HIT_PWALL, 60 | DOOR_FULLOPEN = Wolf.DOOR_FULLOPEN, 61 | XnextTable = Wolf.Math.XnextTable, 62 | YnextTable = Wolf.Math.YnextTable, 63 | getQuadrant = Wolf.Math.getQuadrant, 64 | TanTable = Wolf.Math.TanTable; 65 | 66 | function traceCheck(tileMap, doorMap, visibleTiles, x, y, frac, dfrac, vert, flip, tracePoint) { 67 | var door; 68 | 69 | if (tileMap[x][y] & WALL_TILE) { 70 | if (vert) { 71 | tracePoint.x = (x << TILESHIFT) + (flip ? TILEGLOBAL : 0); 72 | tracePoint.y = (y << TILESHIFT) + frac; 73 | tracePoint.flags |= TRACE_HIT_VERT; 74 | } else { 75 | tracePoint.x = (x << TILESHIFT) + frac; 76 | tracePoint.y = (y << TILESHIFT) + (flip ? TILEGLOBAL : 0); 77 | tracePoint.flags &= ~TRACE_HIT_VERT; 78 | } 79 | tracePoint.tileX = x; 80 | tracePoint.tileY = y; 81 | tracePoint.frac = frac / TILEGLOBAL; 82 | 83 | return true; // wall, stop tracing 84 | } 85 | 86 | if (visibleTiles) { 87 | visibleTiles[x][y] = true; // this tile is visible 88 | } 89 | 90 | if (tileMap[x][y] & DOOR_TILE && doorMap[x][y].action != Wolf.dr_open) { 91 | door = doorMap[x][y]; 92 | 93 | frac += dfrac >> 1; 94 | 95 | if (POS2TILE(frac)) { 96 | return false; 97 | } 98 | 99 | if (vert) { 100 | if (door.action != Wolf.dr_closed && (frac >> 10) > DOOR_FULLOPEN - Wolf.Doors.opened(door)) { 101 | return false; // opened enough 102 | } 103 | tracePoint.x = TILE2POS(x); 104 | tracePoint.y = (y << TILESHIFT) + frac; 105 | tracePoint.flags |= TRACE_HIT_VERT; 106 | tracePoint.frac = frac / TILEGLOBAL; 107 | } else { 108 | if (door.action != Wolf.dr_closed && (frac >> 10) < Wolf.Doors.opened(door)) { 109 | return false; // opened enough 110 | } 111 | tracePoint.y = TILE2POS(y); 112 | tracePoint.x = (x << TILESHIFT) + frac; 113 | tracePoint.flags &= ~TRACE_HIT_VERT; 114 | tracePoint.frac = 1 - frac / TILEGLOBAL; 115 | } 116 | 117 | tracePoint.flags |= TRACE_HIT_DOOR; 118 | tracePoint.tileX = x; 119 | tracePoint.tileY = y; 120 | tracePoint.frac += Wolf.Doors.opened(door) / DOOR_FULLOPEN; 121 | return true; // closed door, stop tracing 122 | } 123 | 124 | 125 | if (tileMap[x][y] & PUSHWALL_TILE) { 126 | 127 | var pwall = Wolf.PushWall.get(), 128 | offset = pwall.pointsMoved / 128; 129 | 130 | frac += dfrac * offset; 131 | 132 | if (POS2TILE(frac)) { 133 | return false; 134 | } 135 | 136 | if (vert) { 137 | tracePoint.x = (x << TILESHIFT) + (flip ? TILEGLOBAL : 0) + offset * TILEGLOBAL * (flip ? -1 : 1); 138 | tracePoint.y = (y << TILESHIFT) + frac; 139 | tracePoint.flags |= TRACE_HIT_VERT; 140 | } else { 141 | tracePoint.x = (x << TILESHIFT) + frac; 142 | tracePoint.y = (y << TILESHIFT) + (flip ? TILEGLOBAL : 0) + offset * TILEGLOBAL * (flip ? -1 : 1); 143 | tracePoint.flags &= ~TRACE_HIT_VERT; 144 | } 145 | 146 | tracePoint.flags |= TRACE_HIT_PWALL; 147 | tracePoint.tileX = x; 148 | tracePoint.tileY = y; 149 | tracePoint.frac = frac / TILEGLOBAL; 150 | return true; 151 | } 152 | 153 | return false; // no intersection, go on! 154 | } 155 | 156 | function trace(level, visibleTiles, tracePoint) { 157 | var xtilestep, ytilestep, 158 | xstep, ystep, 159 | xtile, ytile, 160 | xintercept, yintercept, 161 | YmapPos, XmapPos, 162 | tileMap = level.tileMap, 163 | doorMap = level.state.doorMap, 164 | q; 165 | 166 | // Setup for ray casting 167 | q = getQuadrant(FINE2RAD(tracePoint.angle)); 168 | 169 | xtilestep = x_tile_step[q]; 170 | ytilestep = y_tile_step[q]; 171 | 172 | xtile = POS2TILE(tracePoint.x) + xtilestep; 173 | ytile = POS2TILE(tracePoint.y) + ytilestep; 174 | 175 | xstep = ytilestep * XnextTable[tracePoint.angle]; 176 | ystep = xtilestep * YnextTable[tracePoint.angle]; 177 | 178 | xintercept = (((((ytilestep == -1 ? ytile+1 : ytile) << TILESHIFT) - tracePoint.y) 179 | / TanTable[tracePoint.angle])>>0) + tracePoint.x; 180 | yintercept = (((((xtilestep == -1 ? xtile+1 : xtile) << TILESHIFT) - tracePoint.x) 181 | * TanTable[tracePoint.angle])>>0) + tracePoint.y; 182 | 183 | YmapPos = yintercept >> TILESHIFT; // toXray 184 | XmapPos = xintercept >> TILESHIFT; // toYray 185 | 186 | if (visibleTiles) { 187 | // this tile is visible 188 | visibleTiles[POS2TILE(tracePoint.x)][POS2TILE(tracePoint.y)] = true; 189 | } 190 | 191 | var traceCount = 0; 192 | 193 | // Start of ray-casting 194 | while (1) { 195 | 196 | traceCount++; 197 | 198 | // Vertical loop // an analogue for X-Ray 199 | while (!(ytilestep == -1 && YmapPos <= ytile) && !(ytilestep == 1 && YmapPos >= ytile)) { 200 | 201 | if (xtile < 0 || xtile >= 64 || YmapPos < 0 || YmapPos >= 64) { 202 | tracePoint.oob = true; 203 | return; 204 | } 205 | 206 | if (traceCheck(tileMap, doorMap, visibleTiles, xtile, YmapPos, yintercept % TILEGLOBAL, ystep, true, (xtilestep == -1), tracePoint)) { 207 | if (xstep < 0) { 208 | tracePoint.frac = 1 - tracePoint.frac; 209 | } 210 | return; 211 | } 212 | 213 | // prepare for next step 214 | xtile += xtilestep; 215 | yintercept += ystep; 216 | YmapPos = yintercept >> TILESHIFT; 217 | } 218 | 219 | // Horizontal loop // an analogue for Y-Ray 220 | while (!(xtilestep == -1 && XmapPos <= xtile) && !(xtilestep == 1 && XmapPos >= xtile)) { 221 | 222 | if (ytile < 0 || ytile >= 64 || XmapPos < 0 || XmapPos >= 64) { 223 | tracePoint.oob = true; 224 | return; 225 | } 226 | 227 | if (traceCheck(tileMap, doorMap, visibleTiles, XmapPos, ytile, xintercept % TILEGLOBAL, xstep, false, (ytilestep == -1), tracePoint)) { 228 | if (ystep > 0) { 229 | tracePoint.frac = 1 - tracePoint.frac; 230 | } 231 | return; 232 | } 233 | 234 | // prepare for next step 235 | ytile += ytilestep; 236 | xintercept += xstep; 237 | XmapPos = xintercept >> TILESHIFT; 238 | } 239 | 240 | if (traceCount > 1000) { 241 | return; 242 | } 243 | 244 | } // end of while( 1 ) 245 | 246 | 247 | } 248 | 249 | 250 | function traceRays(viewport, level) { 251 | var n, i, j, 252 | tileMap = level.tileMap, 253 | tracePoint, 254 | visibleTiles = [], 255 | numRays = Wolf.XRES / Wolf.SLICE_WIDTH, 256 | tracers = []; 257 | 258 | for (i=0;i<64;i++) { 259 | visibleTiles[i] = []; 260 | for (j=0;j<64;j++) { 261 | visibleTiles[i][j] = 0; 262 | } 263 | } 264 | 265 | // Ray casting 266 | 267 | for (n = 0 ; n < numRays ; ++n) { 268 | 269 | tracePoint = { 270 | x : viewport.x, 271 | y : viewport.y, 272 | angle : Wolf.Math.normalizeAngle(viewport.angle - Wolf.Math.ColumnAngle[n * Wolf.SLICE_WIDTH]), 273 | flags : Wolf.TRACE_SIGHT | Wolf.TRACE_MARK_MAP, 274 | oob : false 275 | }; 276 | 277 | trace(level, visibleTiles, tracePoint); 278 | 279 | tracers[n] = tracePoint; 280 | 281 | // Ugly hack to get rid of "blank slice" glitch due to out-of-bounds raycasting. 282 | // We simply re-use the previous slice if possible. 283 | if (tracePoint.oob) { 284 | if (n > 0 && !tracers[n-1].oob) { 285 | tracers[n] = tracers[n-1]; 286 | } 287 | } 288 | } 289 | 290 | return { 291 | visibleTiles : visibleTiles, 292 | tracers : tracers 293 | }; 294 | } 295 | 296 | 297 | return { 298 | traceRays : traceRays, 299 | trace : trace 300 | }; 301 | 302 | })(); 303 | -------------------------------------------------------------------------------- /js/renderer.js: -------------------------------------------------------------------------------- 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 . 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 | Wolf.setConsts({ 28 | FOV_RAD : 75 * Math.PI / 180, 29 | ISCHROME : /chrome/.test(navigator.userAgent.toLowerCase()), 30 | ISSAFARI : /safari/.test(navigator.userAgent.toLowerCase()), 31 | ISFIREFOX : /firefox/.test(navigator.userAgent.toLowerCase()), 32 | ISXP : /windows nt 5\./.test(navigator.userAgent.toLowerCase()), 33 | ISWEBKIT : /webkit/.test(navigator.userAgent.toLowerCase()) 34 | }); 35 | Wolf.setConsts({ 36 | VIEW_DIST : (Wolf.XRES / 2) / Math.tan((Wolf.FOV_RAD / 2)), 37 | TEXTURERESOLUTION : Wolf.ISCHROME ? 128 : 64 38 | }); 39 | 40 | 41 | Wolf.Renderer = (function() { 42 | 43 | var slices = [], 44 | useBackgroundImage = Wolf.ISWEBKIT, 45 | texturePath = "art/walls-shaded/" + Wolf.TEXTURERESOLUTION + "/", 46 | spritePath = "art/sprites/" + Wolf.TEXTURERESOLUTION + "/", 47 | sprites = [], 48 | maxDistZ = 64 * 0x10000, 49 | hasInit = false; 50 | visibleSprites = []; 51 | 52 | var TILESHIFT = Wolf.TILESHIFT, 53 | TILEGLOBAL = Wolf.TILEGLOBAL, 54 | TRACE_HIT_VERT = Wolf.TRACE_HIT_VERT, 55 | TRACE_HIT_DOOR = Wolf.TRACE_HIT_DOOR, 56 | WALL_TILE = Wolf.WALL_TILE, 57 | DOOR_TILE = Wolf.DOOR_TILE, 58 | TEX_PLATE = Wolf.TEX_PLATE, 59 | TILE2POS = Wolf.TILE2POS, 60 | POS2TILE = Wolf.POS2TILE, 61 | VIEW_DIST = Wolf.VIEW_DIST, 62 | SLICE_WIDTH = Wolf.SLICE_WIDTH, 63 | WALL_TEXTURE_WIDTH = Wolf.WALL_TEXTURE_WIDTH, 64 | FINE2RAD = Wolf.FINE2RAD, 65 | XRES = Wolf.XRES, 66 | YRES = Wolf.YRES, 67 | MINDIST = Wolf.MINDIST, 68 | cos = Math.cos, 69 | sin = Math.sin, 70 | tan = Math.tan, 71 | atan2 = Math.atan2, 72 | round = Math.round, 73 | sqrt = Math.sqrt; 74 | 75 | function init() { 76 | var image, slice, x; 77 | if (hasInit) { 78 | return; 79 | } 80 | hasInit = true; 81 | 82 | $("#game .renderer") 83 | .width(Wolf.XRES + "px") 84 | .height(Wolf.YRES + "px"); 85 | 86 | for (x=0; x"); 88 | slice.css({ 89 | position : "absolute", 90 | width : Wolf.SLICE_WIDTH + "px", 91 | height : Wolf.YRES + "px", 92 | left : x + "px", 93 | top : 0, 94 | overflow : "hidden" 95 | }); 96 | slice.appendTo("#game .renderer"); 97 | 98 | image = useBackgroundImage ? $("
") : $(""); 99 | 100 | image.css({ 101 | position : "absolute", 102 | display : "block", 103 | top : 0, 104 | height : 0, 105 | width : Wolf.SLICE_WIDTH * Wolf.WALL_TEXTURE_WIDTH + "px", 106 | backgroundSize : "100% 100%" 107 | }); 108 | 109 | var sliceElement = slice[0]; 110 | sliceElement.texture = image[0]; 111 | sliceElement.appendChild(sliceElement.texture); 112 | slices.push(sliceElement); 113 | } 114 | } 115 | 116 | function reset() { 117 | $("#game .renderer .sprite").remove(); 118 | sprites = []; 119 | visibleSprites = []; 120 | } 121 | 122 | function processTrace(viewport, tracePoint) { 123 | var x = tracePoint.x, 124 | y = tracePoint.y, 125 | vx = viewport.x, 126 | vy = viewport.y, 127 | 128 | dx = viewport.x - tracePoint.x, 129 | dy = viewport.y - tracePoint.y, 130 | dist = Math.sqrt(dx*dx + dy*dy), 131 | frac, 132 | h, w, offset; 133 | 134 | // correct for fisheye 135 | dist = dist * cos(FINE2RAD(tracePoint.angle - viewport.angle)); 136 | 137 | w = WALL_TEXTURE_WIDTH * SLICE_WIDTH; 138 | h = (VIEW_DIST / dist * TILEGLOBAL) >> 0; 139 | 140 | if (tracePoint.flags & TRACE_HIT_DOOR) { 141 | if (tracePoint.flags & TRACE_HIT_VERT) { 142 | if (x < vx) { 143 | frac = tracePoint.frac; 144 | } else { 145 | frac = 1 - tracePoint.frac; 146 | } 147 | } else { 148 | if (y < vy) { 149 | frac = 1 - tracePoint.frac; 150 | } else { 151 | frac = tracePoint.frac; 152 | } 153 | } 154 | } else { 155 | frac = 1 - tracePoint.frac; 156 | } 157 | 158 | offset = frac * w; 159 | if (offset > w - SLICE_WIDTH) { 160 | offset = w - SLICE_WIDTH; 161 | } 162 | offset = round(offset / SLICE_WIDTH) * SLICE_WIDTH; 163 | if (offset < 0) { 164 | offset = 0; 165 | } 166 | 167 | return { 168 | w : w, 169 | h : h, 170 | dist : dist, 171 | vert : tracePoint.flags & TRACE_HIT_VERT, 172 | offset : offset 173 | }; 174 | } 175 | 176 | function clear() { 177 | var n, sprite; 178 | for (n=0;n> 0, 209 | height = proc.h, 210 | z = (maxDistZ - proc.dist) >> 0, 211 | itop; 212 | 213 | if (Wolf.ISXP && Wolf.ISFIREFOX) { 214 | itop = (proc.texture % 2) ? 0 : -height; 215 | } else { 216 | itop = -(proc.texture-1) * height; 217 | textureSrc = "art/walls-shaded/64/walls.png"; 218 | } 219 | 220 | if (image._src != textureSrc) { 221 | image._src = textureSrc; 222 | if (useBackgroundImage) { 223 | imgStyle.backgroundImage = "url(" + textureSrc + ")"; 224 | } else { 225 | image.src = textureSrc; 226 | } 227 | } 228 | 229 | if (slice._zIndex != z) { 230 | sliceStyle.zIndex = slice._zIndex = z; 231 | } 232 | if (image._height != height) { 233 | sliceStyle.height = (image._height = height) + "px"; 234 | if (Wolf.ISXP && Wolf.ISFIREFOX) { 235 | imgStyle.height = (height * 2) + "px"; 236 | } else { 237 | imgStyle.height = (height * 120) + "px"; 238 | } 239 | } 240 | 241 | if (image._itop != itop) { 242 | imgStyle.top = (image._itop = itop) + "px"; 243 | } 244 | 245 | if (image._top != top) { 246 | sliceStyle.top = (image._top = top) + "px"; 247 | } 248 | if (image._left != left) { 249 | imgStyle.left = (image._left = left) + "px"; 250 | } 251 | } 252 | 253 | function drawWall(n, viewport, tracePoint, level) { 254 | var x = tracePoint.tileX, 255 | y = tracePoint.tileY, 256 | vx = POS2TILE(viewport.x), 257 | vy = POS2TILE(viewport.y), 258 | tileMap = level.tileMap, 259 | proc = processTrace(viewport, tracePoint), 260 | texture = proc.vert ? level.wallTexX[x][y] : level.wallTexY[x][y], 261 | textureSrc; 262 | 263 | 264 | // door sides 265 | if (tracePoint.flags & TRACE_HIT_VERT) { 266 | if (x >= vx && tileMap[x-1][y] & DOOR_TILE) { 267 | texture = TEX_PLATE; 268 | } 269 | if (x < vx && tileMap[x+1][y] & DOOR_TILE) { 270 | texture = TEX_PLATE; 271 | } 272 | } else { 273 | if (y >= vy && tileMap[x][y-1] & DOOR_TILE) { 274 | texture = TEX_PLATE; 275 | } 276 | if (y < vy && tileMap[x][y+1] & DOOR_TILE) { 277 | texture = TEX_PLATE; 278 | } 279 | } 280 | 281 | texture++; 282 | 283 | proc.texture = texture; 284 | 285 | if (texture % 2 == 0) { 286 | texture--; 287 | } 288 | textureSrc = texturePath + "w_" + texture + ".png"; 289 | 290 | updateSlice(n, textureSrc, proc); 291 | } 292 | 293 | function drawDoor(n, viewport, tracePoint, level) { 294 | var proc = processTrace(viewport, tracePoint), 295 | texture, textureSrc; 296 | 297 | //texture = Wolf.TEX_DDOOR + 1; 298 | texture = level.state.doorMap[tracePoint.tileX][tracePoint.tileY].texture + 1; 299 | 300 | proc.texture = texture; 301 | 302 | if (texture % 2 == 0) { 303 | texture -= 1; 304 | } 305 | 306 | textureSrc = texturePath + "w_" + texture + ".png"; 307 | 308 | updateSlice(n, textureSrc, proc); 309 | } 310 | 311 | function drawSprites(viewport, level, visibleTiles) { 312 | var vis, n, 313 | dist, dx, dy, angle, 314 | z, width, size, 315 | div, image, 316 | divStyle, imgStyle; 317 | 318 | 319 | // build visible sprites list 320 | visibleSprites = Wolf.Sprites.createVisList(viewport, level, visibleTiles); 321 | 322 | for (n = 0; n < visibleSprites.length; ++n ){ 323 | vis = visibleSprites[n]; 324 | dist = vis.dist; 325 | 326 | if (dist < MINDIST / 2 ) { 327 | //continue; // little hack to save speed & z-buffer 328 | } 329 | 330 | // make sure sprite is loaded 331 | if (!vis.sprite.div) { 332 | loadSprite(vis.sprite) 333 | } 334 | 335 | div = vis.sprite.div; 336 | divStyle = div.style; 337 | 338 | image = div.image; 339 | imgStyle = image.style; 340 | 341 | dx = vis.sprite.x - viewport.x; 342 | dy = vis.sprite.y - viewport.y; 343 | angle = atan2(dy, dx) - FINE2RAD(viewport.angle); 344 | 345 | //dist = dist * Math.cos(angle); 346 | 347 | size = (VIEW_DIST / dist * TILEGLOBAL) >> 0; 348 | 349 | divStyle.display = "block"; 350 | divStyle.width = size + "px"; 351 | divStyle.height = size + "px"; 352 | 353 | divStyle.left = (XRES / 2 - size / 2 - tan(angle) * VIEW_DIST) + "px"; 354 | 355 | divStyle.top = (YRES / 2 - size / 2) + "px"; 356 | 357 | texture = Wolf.Sprites.getTexture(vis.sprite.tex[0]); 358 | textureSrc = spritePath + texture.sheet; 359 | 360 | if (image._src != textureSrc) { 361 | image._src = textureSrc; 362 | if (useBackgroundImage) { 363 | imgStyle.backgroundImage = "url(" + textureSrc + ")"; 364 | } else { 365 | image.src = textureSrc; 366 | } 367 | } 368 | 369 | z = (maxDistZ - dist) >> 0; 370 | width = texture.num * size; 371 | left = -texture.idx * size; 372 | 373 | if (div._zIndex != z) { 374 | divStyle.zIndex = div._zIndex = z; 375 | } 376 | if (image._width != width) { 377 | imgStyle.width = (image._width = width) + "px"; 378 | } 379 | if (image._height != size) { 380 | imgStyle.height = (image._height = size) + "px"; 381 | } 382 | if (image._left != left) { 383 | imgStyle.left = (image._left = left) + "px"; 384 | } 385 | } 386 | } 387 | 388 | function unloadSprite(sprite) { 389 | if (sprite.div) { 390 | $(sprite.div).remove(); 391 | sprite.div = null; 392 | } 393 | } 394 | 395 | function loadSprite(sprite) { 396 | var div = document.createElement("div"), 397 | image; 398 | 399 | div.style.display = "none"; 400 | div.style.position = "absolute"; 401 | div.style.width = "128px"; 402 | div.style.height = "128px"; 403 | div.style.overflow = "hidden"; 404 | div.className = "sprite"; 405 | 406 | image = useBackgroundImage ? $("
") : $(""); 407 | 408 | image.css({ 409 | position : "absolute", 410 | display : "block", 411 | top : 0, 412 | height : "100%", 413 | width : "100%", 414 | backgroundSize : "100%", 415 | backgroundRepeat : "no-repeat" 416 | }); 417 | 418 | div.image = image[0]; 419 | div.appendChild(div.image); 420 | 421 | sprite.div = div; 422 | $("#game .renderer").append(div); 423 | } 424 | 425 | return { 426 | init : init, 427 | draw : draw, 428 | clear : clear, 429 | loadSprite : loadSprite, 430 | unloadSprite : unloadSprite, 431 | reset : reset 432 | }; 433 | 434 | })(); 435 | -------------------------------------------------------------------------------- /js/requestanimframe.js: -------------------------------------------------------------------------------- 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 . 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 | 28 | /* requestAnimationFrame polyfill */ 29 | (function() { 30 | 31 | window.requestAnimationFrame = (function() { 32 | return window.requestAnimationFrame 33 | || window.webkitRequestAnimationFrame 34 | || window.mozRequestAnimationFrame 35 | || window.oRequestAnimationFrame 36 | || window.msRequestAnimationFrame 37 | || function(callback, element) { 38 | return window.setTimeout( 39 | function() { 40 | callback(Date.now()); 41 | }, 1000 / 60 42 | ); 43 | }; 44 | })(); 45 | 46 | window.cancelRequestAnimationFrame = (function() { 47 | return window.cancelRequestAnimationFrame 48 | || window.webkitCancelRequestAnimationFrame 49 | || window.mozCancelRequestAnimationFrame 50 | || window.oCancelRequestAnimationFrame 51 | || window.msCancelRequestAnimationFrame 52 | || window.clearTimeout; 53 | })(); 54 | 55 | })(); 56 | 57 | -------------------------------------------------------------------------------- /js/sound.js: -------------------------------------------------------------------------------- 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 . 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 | Wolf.Sound = (function() { 28 | 29 | Wolf.setConsts({ 30 | // Sound channels 31 | // Channel 0 never willingly overrides 32 | // Other channels (1-7) always override a playing sound on that channel 33 | CHAN_AUTO : 0, 34 | CHAN_WEAPON : 1, 35 | CHAN_VOICE : 2, 36 | CHAN_ITEM : 3, 37 | CHAN_BODY : 4, 38 | // Modifier flags 39 | CHAN_NO_PHS_ADD : 8, // Send to all clients, not just ones in PHS (ATTN 0 will also do this) 40 | CHAN_RELIABLE : 16, // Send by reliable message, not datagram 41 | // Sound attenuation values 42 | ATTN_NONE : 0, // Full volume the entire level 43 | ATTN_NORM : 1, 44 | ATTN_IDLE : 2, 45 | ATTN_STATIC : 3, // Diminish very rapidly with distance 46 | 47 | MAX_PLAYSOUNDS : 128, 48 | MAX_CHANNELS : 64, 49 | 50 | MUSIC_VOLUME : 0.8, 51 | MASTER_VOLUME : 0.6 52 | }); 53 | 54 | var sounds = {}, 55 | audioElements = [], 56 | currentMusic, 57 | soundEnabled = true, 58 | musicEnabled = true, 59 | music, 60 | ext, 61 | exts = ["ogg", "mp3"]; 62 | 63 | function getFileName(file) { 64 | if (!ext) { 65 | // look for a probably 66 | for (var i=0;i 0) { 136 | audioElements[i].currentTime = 0; 137 | audioElements[i].pause(); 138 | } 139 | } 140 | } 141 | 142 | function init() { 143 | } 144 | 145 | 146 | function isMusicEnabled() { 147 | return musicEnabled 148 | } 149 | 150 | function isSoundEnabled() { 151 | return soundEnabled; 152 | } 153 | 154 | function toggleMusic(enable) { 155 | if (typeof enable != "undefined") { 156 | musicEnabled = enable; 157 | } else { 158 | musicEnabled = !musicEnabled; 159 | } 160 | if (music) { 161 | music.volume = Wolf.MUSIC_VOLUME * Wolf.MASTER_VOLUME * (musicEnabled ? 1 : 0); 162 | } 163 | } 164 | 165 | function pauseMusic(enable) { 166 | if (music) { 167 | if (enable) { 168 | music.pause(); 169 | } else if (music.paused) { 170 | music.play(); 171 | } 172 | } 173 | } 174 | 175 | function toggleSound(enable) { 176 | if (typeof enable != "undefined") { 177 | soundEnabled = enable; 178 | } else { 179 | soundEnabled = !soundEnabled; 180 | } 181 | } 182 | 183 | if (Modernizr.audio) { 184 | return { 185 | startSound : startSound, 186 | startMusic : startMusic, 187 | stopAllSounds : stopAllSounds, 188 | isMusicEnabled : isMusicEnabled, 189 | isSoundEnabled : isSoundEnabled, 190 | toggleMusic : toggleMusic, 191 | toggleSound : toggleSound, 192 | pauseMusic : pauseMusic, 193 | init : init 194 | } 195 | } else { 196 | return { 197 | startSound : Wolf.noop, 198 | startMusic : Wolf.noop, 199 | stopAllSounds : Wolf.noop, 200 | isMusicEnabled : Wolf.noop, 201 | isSoundEnabled : Wolf.noop, 202 | toggleMusic : Wolf.noop, 203 | toggleSound : Wolf.noop, 204 | pauseMusic : Wolf.noop, 205 | init : Wolf.noop 206 | } 207 | } 208 | })(); -------------------------------------------------------------------------------- /js/weapon.js: -------------------------------------------------------------------------------- 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 . 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 | /** 28 | * @namespace 29 | * @description Weapons 30 | */ 31 | Wolf.Weapon = (function() { 32 | 33 | 34 | function fireHit(game, player) { 35 | var level = game.level, 36 | closest, 37 | dist, 38 | d1, 39 | n, 40 | shotDist, 41 | damage, 42 | guard; 43 | 44 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "lsfx/023.wav", 1, Wolf.ATTN_NORM, 0); 45 | 46 | // actually fire 47 | dist = 0x7fffffff; 48 | closest = null; 49 | 50 | for (n=0; n (2 * Wolf.TILEGLOBAL / 3)) { 56 | continue; // miss 57 | } 58 | 59 | d1 = Wolf.Math.lineLen2Point(guard.x - player.position.x, guard.y - player.position.y, player.angle); 60 | 61 | if (d1 < 0 || d1 > dist) { 62 | continue; 63 | } 64 | 65 | if (!Wolf.Level.checkLine(guard.x, guard.y, player.position.x, player.position.y, level)) { 66 | continue; // obscured 67 | } 68 | dist = d1; 69 | closest = guard; 70 | } 71 | } 72 | 73 | if (!closest || dist > Wolf.TILE2POS(1)) { 74 | return; // missed if further than 1.5 tiles 75 | } 76 | 77 | damage = Wolf.Random.rnd() >> 4; 78 | 79 | Wolf.ActorAI.damageActor(closest, game, player, damage); // hit something 80 | } 81 | 82 | 83 | function fireLead(game, player) { 84 | var level = game.level, 85 | closest, 86 | damage, 87 | dx, dy, dist, 88 | d1, shotDist, n, 89 | guard; 90 | 91 | switch (player.weapon) { 92 | case Wolf.WEAPON_PISTOL: 93 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "sfx/012.wav", 1, Wolf.ATTN_NORM, 0); 94 | break; 95 | 96 | case Wolf.WEAPON_AUTO: 97 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "sfx/011.wav", 1, Wolf.ATTN_NORM, 0); 98 | break; 99 | 100 | case Wolf.WEAPON_CHAIN: 101 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "sfx/013.wav", 1, Wolf.ATTN_NORM, 0); 102 | break; 103 | } 104 | 105 | player.madenoise = true; 106 | 107 | dist = 0x7fffffff; 108 | closest = null; 109 | 110 | for (n=0;n < level.state.numGuards; ++n) { 111 | guard = level.state.guards[n]; 112 | if (guard.flags & Wolf.FL_SHOOTABLE ) { // && Guards[n].flags&FL_VISABLE 113 | shotDist = Wolf.Math.point2LineDist(guard.x - player.position.x, guard.y - player.position.y, player.angle); 114 | if (shotDist > (2 * Wolf.TILEGLOBAL / 3)) { 115 | continue; // miss 116 | } 117 | 118 | d1 = Wolf.Math.lineLen2Point(guard.x - player.position.x, guard.y - player.position.y, player.angle); 119 | if (d1 < 0 || d1 > dist) { 120 | continue; 121 | } 122 | if (!Wolf.Level.checkLine(guard.x, guard.y, player.position.x, player.position.y, level)) { 123 | continue; // obscured 124 | } 125 | 126 | dist = d1; 127 | closest = guard; 128 | } 129 | } 130 | 131 | if (!closest) { // missed 132 | var tracePoint = { 133 | angle : Wolf.Math.normalizeAngle(player.angle - Wolf.DEG2FINE(2) + (Math.random() * 0x10000) % (Wolf.DEG2FINE(4))), 134 | x : player.position.x, 135 | y : player.position.y, 136 | flags : Wolf.TRACE_BULLET 137 | } 138 | 139 | Wolf.Raycaster.trace(level, null, tracePoint); 140 | 141 | if (tracePoint.flags & Wolf.TRACE_HIT_DOOR) { 142 | Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_AUTO, "lsfx/028.wav", 1, Wolf.ATTN_NORM, 0); 143 | } 144 | 145 | return; 146 | } 147 | 148 | // hit something 149 | dx = Math.abs(closest.tile.x - player.tile.x); 150 | dy = Math.abs(closest.tile.y - player.tile.y); 151 | dist = Math.max(dx, dy); 152 | 153 | if (dist < 2) { 154 | damage = Wolf.Random.rnd() / 4; 155 | } else if (dist < 4) { 156 | damage = Wolf.Random.rnd() / 6; 157 | } else { 158 | if (Wolf.Random.rnd() / 12 < dist) { 159 | return; // missed 160 | } 161 | damage = Wolf.Random.rnd() / 6; 162 | } 163 | 164 | Wolf.ActorAI.damageActor(closest, game, player, damage); 165 | } 166 | 167 | 168 | 169 | return { 170 | fireHit : fireHit, 171 | fireLead : fireLead 172 | }; 173 | 174 | 175 | })(); -------------------------------------------------------------------------------- /js/wolf.js: -------------------------------------------------------------------------------- 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 . 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 | var Wolf = { 29 | 30 | XRES : 608, 31 | YRES : 304, 32 | SLICE_WIDTH : 3, 33 | WALL_TEXTURE_WIDTH : 64, 34 | NUM_WALL_TEXTURES : 55, 35 | HUD_FACE_WIDTH : 48, 36 | HUD_FACE_HEIGHT : 64, 37 | HUD_WEAPON_WIDTH : 256, 38 | 39 | 40 | NUMAREAS : 37, // number of areas 41 | FIRSTAREA : 0x6B, // first area in map data (it is by the way a way to the secret floor!) 42 | AMBUSHTILE : 0x6A, // def guard 43 | AMBUSH : -2, 44 | 45 | TILEGLOBAL : 0x10000, 46 | HALFTILE : 0x8000, 47 | TILESHIFT : 16, 48 | MINDIST : 0x5800, 49 | FLOATTILE : 65536.0, 50 | 51 | TILE2POS : function(a) { return (((a)<>Wolf.TILESHIFT); }, 53 | POS2TILEf : function(a) { return ((a)/Wolf.FLOATTILE); }, 54 | 55 | ASTEP : 0.0078125, // 1 FINE=x DEGREES 56 | ASTEPRAD : 0.000136354, // 1 FINE=x RADIANS 57 | ANG_1RAD : 7333.8598, // 1 RADIAN=x FINES 58 | ANG_0 : 0, //(int)((float)0/ASTEP) 59 | ANG_1 : 128, //(int)((float)1/ASTEP) 60 | ANG_6 : 768, //(int)((float)6/ASTEP) 61 | ANG_15 : 1920, //(int)((float)15/ASTEP) 62 | ANG_22_5 : 2880, //(int)((float)22.5/ASTEP) 63 | ANG_30 : 3840, //(int)((float)30/ASTEP) 64 | ANG_45 : 5760, //(int)((float)45/ASTEP) 65 | ANG_67_5 : 8640, //(int)((float)67.5/ASTEP) 66 | ANG_90 : 11520, //(int)((float)90/ASTEP) 67 | ANG_112_5 : 14400, //(int)((float)112.5/ASTEP) 68 | ANG_135 : 17280, //(int)((float)135/ASTEP) 69 | ANG_157_5 : 20160, //(int)((float)157.5/ASTEP) 70 | ANG_180 : 23040, //(int)((float)180/ASTEP) 71 | ANG_202_5 : 25920, //(int)((float)202.5/ASTEP) 72 | ANG_225 : 28800, //(int)((float)225/ASTEP) 73 | ANG_247_5 : 31680, //(int)((float)247.5/ASTEP) 74 | ANG_270 : 34560, //(int)((float)270/ASTEP) 75 | ANG_292_5 : 37440, //(int)((float)292.5/ASTEP) 76 | ANG_315 : 40320, //(int)((float)225/ASTEP) 77 | ANG_337_5 : 43200, //(int)((float)337.5/ASTEP) 78 | ANG_360 : 46080, //(int)((float)360/ASTEP) 79 | 80 | ANGLES : 360, // must be divisable by 4 81 | DEATHROTATE : 2, 82 | 83 | FINE2RAD : function(a) { return (a * Math.PI / Wolf.ANG_180); }, 84 | RAD2FINE : function(a) { return (a * Wolf.ANG_180 / Math.PI); }, 85 | FINE2DEG : function(a) { return (a / Wolf.ANG_1) >> 0; }, // !@# don't lose precision bits 86 | FINE2DEGf : function(a) { return (a / Wolf.ANG_1); }, 87 | DEG2FINE : function(a) { return (a * Wolf.ANG_1); } 88 | 89 | }; 90 | 91 | Wolf.setConsts = function(C) { 92 | for (var a in C) { 93 | if (C.hasOwnProperty(a) && !(a in Wolf)) { 94 | Wolf[a] = C[a]; 95 | } 96 | } 97 | }; 98 | 99 | Wolf.noop = function() {}; 100 | 101 | Wolf.log = function(str) { 102 | /* 103 | if (typeof console != "undefined") { 104 | var t = new Date(), 105 | e = new Error(), 106 | f = ""; 107 | if (typeof str == "object" && typeof e.stack == "string") { 108 | // ugly hack to get some kind of reference to where the log call originated 109 | var s = e.stack.split("\n")[2]+"", 110 | m = s.match(/at (.*)$/); 111 | f = m ? "\t[" + m[1] + "]" : ""; 112 | } 113 | console.log(t.toLocaleTimeString() + ": " + str + f); 114 | } 115 | */ 116 | }; 117 | 118 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 id Software LLC, a ZeniMax Media company. 3 | * 4 | * This file is part of the WOLF3D Browser Version GPL Source Code. 5 | * 6 | */ 7 | 8 | html { 9 | padding : 0; 10 | background-color : black; 11 | } 12 | 13 | body { 14 | margin : 0; 15 | padding : 0; 16 | -webkit-touch-callout:none; 17 | -webkit-tap-highlight-color: rgba(0,0,0,0); 18 | -webkit-text-size-adjust: none; 19 | 20 | -webkit-user-select:none; 21 | -moz-user-select:none; 22 | -ms-user-select:none; 23 | user-select:none; 24 | 25 | width : 100%; 26 | height : 100%; 27 | } 28 | 29 | .load-progress { 30 | position : absolute; 31 | left : 0; 32 | bottom : 0; 33 | height : 5px; 34 | width : 0; 35 | background-color : #666; 36 | } 37 | 38 | 39 | #main { 40 | position : absolute; 41 | left : 0; 42 | top : 0; 43 | width : 640px; 44 | height : 400px; 45 | left : 50%; 46 | top : 50%; 47 | margin-left : -320px; 48 | margin-top : -200px; 49 | overflow : hidden; 50 | } 51 | 52 | #game, #menu, #title-screen { 53 | position : absolute; 54 | left : 0; 55 | top : 0; 56 | width : 100%; 57 | height : 100%; 58 | display : none; 59 | background-repeat : no-repeat; 60 | } 61 | 62 | #title-screen { 63 | background-image : url(art/title.png); 64 | display : block; 65 | } 66 | 67 | #game { 68 | background-color : rgb(0,56,56); 69 | background-image : url(art/gamebg.png); 70 | } 71 | 72 | 73 | 74 | #game .loading { 75 | background-color : rgb(0,56,56); 76 | display : none; 77 | position : absolute; 78 | left : 0; 79 | top : 0; 80 | width : 100%; 81 | height : 320px; 82 | z-index : 60; 83 | } 84 | #game .loading img { 85 | position : absolute; 86 | left : 50%; 87 | top : 50%; 88 | margin-left : -224px; 89 | margin-top : -48px; 90 | } 91 | 92 | 93 | #game .renderer { 94 | z-index : 50; 95 | background-color : #222; 96 | overflow : hidden; 97 | position : absolute; 98 | left : 16px; 99 | top : 8px; 100 | cursor : crosshair; 101 | } 102 | 103 | #game *, 104 | #game .renderer div, 105 | #game .renderer div img, 106 | #game .renderer .sprite, 107 | #game .renderer .sprite img { 108 | image-rendering : optimizeSpeed; 109 | image-rendering : -moz-crisp-edges; 110 | image-rendering : -o-crisp-edges; 111 | image-rendering : optimize-contrast; 112 | image-rendering : -webkit-optimize-contrast; 113 | -ms-interpolation-mode: nearest-neighbor; 114 | } 115 | 116 | #game .renderer .player-weapon { 117 | z-index : 100000000; 118 | width : 256px; 119 | height : 256px; 120 | position : absolute; 121 | bottom : 0; 122 | left : 50%; 123 | margin-left : -128px; 124 | background-image : url(art/attack.png); 125 | background-repeat : no-repeat; 126 | } 127 | 128 | 129 | #game .renderer .overlay { 130 | z-index : 200000000; 131 | width : 100%; 132 | height : 100%; 133 | position : absolute; 134 | top : 0; 135 | left : 0; 136 | display : none; 137 | } 138 | 139 | #game .renderer .damage-flash { 140 | background : rgba(255,0,0,0.25); 141 | } 142 | #game .renderer .bonus-flash { 143 | background : rgba(255,255,128,0.20); 144 | } 145 | #game .renderer .death { 146 | background : rgba(255,0,0,0); 147 | } 148 | 149 | #game .renderer .pause { 150 | background : rgba(32,32,32,0.5); 151 | } 152 | #game .renderer .pause img { 153 | position : absolute; 154 | left : 50%; 155 | top : 50%; 156 | margin-left : -64px; 157 | margin-top : -32px; 158 | } 159 | 160 | 161 | #game .ceiling, #game .floor { 162 | position : absolute; 163 | z-index : 0; 164 | left : 0; 165 | width : 100%; 166 | height : 50%; 167 | } 168 | 169 | #game .ceiling { 170 | top : 0; 171 | } 172 | 173 | #game .floor{ 174 | top : 50%; 175 | } 176 | 177 | #game .hud { 178 | position : absolute; 179 | z-index : 100; 180 | bottom : 0; 181 | width : 640px; 182 | height : 80px; 183 | background-image : url(art/hudbg.png); 184 | } 185 | 186 | #game .hud .bj { 187 | position : absolute; 188 | width : 48px; 189 | height : 64px; 190 | left : 273px; 191 | top : 9px; 192 | overflow : hidden; 193 | background-image : url(art/bj.png); 194 | } 195 | 196 | #game .hud .key1, 197 | #game .hud .key2 { 198 | position : absolute; 199 | width : 16px; 200 | height : 32px; 201 | left : 480px; 202 | overflow : hidden; 203 | background-image : url(art/hudkeys.png); 204 | } 205 | 206 | #game .hud .key1 { 207 | top : 8px; 208 | } 209 | #game .hud .key2 { 210 | top : 40px; 211 | background-position : -16px 0; 212 | } 213 | 214 | 215 | #game .hud .weapon { 216 | position : absolute; 217 | width : 96px; 218 | height : 48px; 219 | left : 512px; 220 | top : 16px; 221 | overflow : hidden; 222 | background-image : url(art/hudweapons.png); 223 | } 224 | 225 | #game .hud .number-container { 226 | position : absolute; 227 | height : 32px; 228 | top : 32px; 229 | } 230 | 231 | #game .hud .floor { 232 | left : 48px; 233 | } 234 | #game .hud .score { 235 | left : 96px; 236 | } 237 | #game .hud .lives { 238 | left : 224px; 239 | } 240 | #game .hud .health { 241 | left : 336px; 242 | } 243 | #game .hud .ammo { 244 | left : 428px; 245 | } 246 | 247 | 248 | #game .hud .number { 249 | display : inline-block; 250 | width : 16px; 251 | height : 32px; 252 | overflow : hidden; 253 | margin : 0; 254 | background-image : url(art/hudnumbers.png); 255 | background-repeat : no-repeat; 256 | } 257 | 258 | #game .fps { 259 | position : absolute; 260 | display : none; 261 | z-index : 1000; 262 | left : 20px; 263 | top : 15px; 264 | font-family : courier new; 265 | font-size : 16px; 266 | width : 70px; 267 | height : 16px; 268 | background : rgba(0,0,0,0.3); 269 | color : rgb(200,200,200); 270 | padding : 5px; 271 | } 272 | 273 | 274 | #text-screen { 275 | background-color : #8a0000; 276 | position : absolute; 277 | height : 100%; 278 | width : 100%; 279 | left : 0; 280 | top : 0; 281 | z-index : 500; 282 | display : none; 283 | } 284 | 285 | #game .intermission, 286 | #game .gameover { 287 | position : absolute; 288 | height : 100%; 289 | width : 100%; 290 | left : 0; 291 | top : 0; 292 | background-color : #004141; 293 | display : none; 294 | } 295 | 296 | #game .gameover { 297 | background-image : url(art/intermission_gameover.png); 298 | } 299 | 300 | #game .intermission > div { 301 | position : absolute; 302 | } 303 | 304 | #game .intermission .background, 305 | #game .intermission .background-secret, 306 | #game .intermission .background-victory { 307 | position : absolute; 308 | background-image : url(art/intermission.png); 309 | height : 100%; 310 | width : 100%; 311 | left : 0; 312 | top : 0; 313 | z-index : 0; 314 | display : none; 315 | } 316 | #game .intermission .background-secret { 317 | background-image : url(art/intermission_secret.png); 318 | } 319 | #game .intermission .background-victory { 320 | background-image : url(art/intermission_victory.png); 321 | } 322 | 323 | #game .intermission .bj { 324 | left : 40px; 325 | top : 32px; 326 | width : 162px; 327 | height : 174px; 328 | background-image : url(art/intermissionbj.png); 329 | overflow : hidden; 330 | z-index : 10; 331 | } 332 | 333 | #game .intermission .stat, 334 | #game .intermission .victory-stat { 335 | z-index : 10; 336 | } 337 | 338 | #game .intermission .bonus { 339 | left : 412px; 340 | top : 108px; 341 | } 342 | 343 | #game .intermission .floor { 344 | left : 412px; 345 | top : 32px; 346 | } 347 | 348 | 349 | #game .intermission .total-time-minutes { 350 | top : 128px; 351 | left : 224px; 352 | } 353 | 354 | #game .intermission .total-time-seconds { 355 | top : 128px; 356 | left : 306px; 357 | } 358 | 359 | 360 | #game .intermission .time-minutes, 361 | #game .intermission .par-minutes { 362 | left : 412px; 363 | } 364 | 365 | #game .intermission .time-seconds, 366 | #game .intermission .par-seconds { 367 | left : 498px; 368 | } 369 | 370 | #game .intermission .time-minutes, 371 | #game .intermission .time-seconds { 372 | top : 152px; 373 | } 374 | 375 | #game .intermission .par-minutes, 376 | #game .intermission .par-seconds { 377 | top : 184px; 378 | } 379 | 380 | #game .intermission .kill-ratio, 381 | #game .intermission .secret-ratio, 382 | #game .intermission .treasure-ratio { 383 | left : 492px; 384 | } 385 | #game .intermission .kill-ratio { 386 | top : 224px; 387 | } 388 | #game .intermission .secret-ratio { 389 | top : 256px; 390 | } 391 | #game .intermission .treasure-ratio { 392 | top : 288px; 393 | } 394 | 395 | #game .intermission .avg-kill-ratio, 396 | #game .intermission .avg-secret-ratio, 397 | #game .intermission .avg-treasure-ratio { 398 | left : 384px; 399 | } 400 | #game .intermission .avg-kill-ratio { 401 | top : 224px; 402 | } 403 | #game .intermission .avg-secret-ratio { 404 | top : 256px; 405 | } 406 | #game .intermission .avg-treasure-ratio { 407 | top : 288px; 408 | } 409 | 410 | #game .intermission .digit { 411 | display : inline-block; 412 | width : 32px; 413 | height : 32px; 414 | background-image : url(art/intermissionfont.png); 415 | background-repeat : no-repeat; 416 | background-position : 32px 0px; 417 | } 418 | #game .intermission .num-0 { 419 | background-position : 0px 0px; 420 | } 421 | #game .intermission .num-1 { 422 | background-position : -32px 0px; 423 | } 424 | #game .intermission .num-2 { 425 | background-position : -64px 0px; 426 | } 427 | #game .intermission .num-3 { 428 | background-position : -96px 0px; 429 | } 430 | #game .intermission .num-4 { 431 | background-position : -128px 0px; 432 | } 433 | #game .intermission .num-5 { 434 | background-position : -160px 0px; 435 | } 436 | #game .intermission .num-6 { 437 | background-position : -192px 0px; 438 | } 439 | #game .intermission .num-7 { 440 | background-position : -224px 0px; 441 | } 442 | #game .intermission .num-8 { 443 | background-position : -256px 0px; 444 | } 445 | #game .intermission .num-9 { 446 | background-position : -288px 0px; 447 | } 448 | 449 | #menu div.menu { 450 | width : 100%; 451 | height : 100%; 452 | } 453 | 454 | #menu div.menu.main { 455 | background-image : url(art/menubg_main.png); 456 | } 457 | 458 | #menu div.menu.episodes { 459 | background-image : url(art/menubg_episodes.png); 460 | } 461 | 462 | #menu div.menu.levels { 463 | background-image : url(art/menubg_levels.png); 464 | } 465 | 466 | #menu div.menu.skill { 467 | background-image : url(art/menubg_skill.png); 468 | } 469 | 470 | 471 | #menu div.menu.sound { 472 | background-image : url(art/menubg_sound.png); 473 | } 474 | 475 | #menu div.menu.control { 476 | background-image : url(art/menubg_control.png); 477 | } 478 | 479 | #menu div.menu.customize { 480 | background-image : url(art/menubg_customize.png); 481 | } 482 | 483 | #menu ul { 484 | list-style : none; 485 | margin : 0; 486 | padding : 0; 487 | position : absolute; 488 | } 489 | 490 | #menu div.menu.main ul { 491 | left : 196px; 492 | top : 118px; 493 | width : 330px; 494 | height : 232px; 495 | } 496 | 497 | #menu div.menu.sound ul { 498 | left : 150px; 499 | top : 87px; 500 | width : 330px; 501 | height : 232px; 502 | } 503 | 504 | #menu div.menu.episodes ul { 505 | left : 44px; 506 | top : 100px; 507 | width : 550px; 508 | height : 240px; 509 | } 510 | 511 | #menu div.menu.skill ul { 512 | left : 144px; 513 | top : 186px; 514 | width : 384px; 515 | height : 128px; 516 | } 517 | 518 | 519 | #menu div.menu.levels ul { 520 | left : 90px; 521 | top : 110px; 522 | width : 256px; 523 | height : 240px; 524 | } 525 | 526 | #menu div.menu.control ul { 527 | left : 160px; 528 | top : 156px; 529 | width : 350px; 530 | height : 100px; 531 | } 532 | 533 | #menu div.menu.customize ul { 534 | left : 116px; 535 | top : 192px; 536 | width : 512px; 537 | height : 96px; 538 | } 539 | 540 | 541 | #menu ul.two-column{ 542 | position : relative; 543 | float : left; 544 | width : 256px; 545 | } 546 | 547 | /* menu items */ 548 | 549 | #menu ul li div.button { 550 | display : block; 551 | height : 24px; 552 | cursor : pointer; 553 | margin-bottom : 8px; 554 | background-image : url(art/menuitems.png); 555 | } 556 | 557 | #menu li.newgame div.button { 558 | background-position : 0 0; 559 | } 560 | #menu li.active.newgame div.button { 561 | background-position : -384px 0; 562 | } 563 | 564 | #menu li.sound div.button { 565 | background-position : 0 -32px; 566 | } 567 | #menu li.active.sound div.button { 568 | background-position : -384px -32px; 569 | } 570 | 571 | #menu li.control div.button { 572 | background-position : 0 -64px; 573 | } 574 | #menu li.active.control div.button { 575 | background-position : -384px -64px; 576 | } 577 | 578 | #menu li.readthis div.button { 579 | background-position : 0 -96px; 580 | } 581 | #menu li.active.readthis div.button { 582 | background-position : -384px -96px; 583 | } 584 | 585 | #menu li.resumegame div.button { 586 | background-position : 0 -128px; 587 | } 588 | #menu li.active.resumegame div.button { 589 | background-position : -384px -128px; 590 | } 591 | 592 | #menu li.baby div.button { 593 | background-position : 0 -160px; 594 | } 595 | #menu li.active.baby div.button { 596 | background-position : -384px -160px; 597 | } 598 | 599 | #menu li.easy div.button { 600 | background-position : 0 -192px; 601 | } 602 | #menu li.active.easy div.button { 603 | background-position : -384px -192px; 604 | } 605 | 606 | #menu li.medium div.button { 607 | background-position : 0 -224px; 608 | } 609 | #menu li.active.medium div.button { 610 | background-position : -384px -224px; 611 | } 612 | 613 | #menu li.hard div.button { 614 | background-position : 0 -256px; 615 | } 616 | #menu li.active.hard div.button { 617 | background-position : -384px -256px; 618 | } 619 | 620 | #menu li.sfxoff { 621 | margin-bottom : 58px; 622 | } 623 | 624 | #menu li.sfxon div.button, 625 | #menu li.musicon div.button, 626 | #menu li.sfxoff div.button, 627 | #menu li.musicoff div.button { 628 | margin-left : 48px; 629 | width : 256px; 630 | } 631 | 632 | 633 | #menu li.sfxon div.button, 634 | #menu li.musicon div.button { 635 | background-position : 0 -288px; 636 | } 637 | #menu li.active.sfxon div.button, 638 | #menu li.active.musicon div.button { 639 | background-position : -384px -288px; 640 | } 641 | 642 | #menu li.sfxoff div.button, 643 | #menu li.musicoff div.button { 644 | background-position : 0 -320px; 645 | } 646 | #menu li.active.sfxoff div.button, 647 | #menu li.active.musicoff div.button { 648 | background-position : -384px -320px; 649 | } 650 | 651 | #menu li.mouseenabled div.button { 652 | background-position : 0 -352px; 653 | } 654 | #menu li.active.mouseenabled div.button { 655 | background-position : -384px -352px; 656 | } 657 | #menu li.customize div.button { 658 | background-position : 0 -384px; 659 | } 660 | #menu li.active.customize div.button { 661 | background-position : -384px -384px; 662 | } 663 | 664 | #menu div.menu.episodes li div.button { 665 | height : 56px; 666 | width : 550px; 667 | background-image : url(art/menuitems_episodes.png); 668 | } 669 | 670 | #menu div.menu.episodes li.episode-0 div.button { 671 | background-position : 0 0; 672 | } 673 | #menu div.menu.episodes li.active.episode-0 div.button { 674 | background-position : 0 -56px; 675 | } 676 | 677 | #menu div.menu.episodes li.episode-1 div.button { 678 | background-position : 0 -112px; 679 | } 680 | #menu div.menu.episodes li.active.episode-1 div.button { 681 | background-position : 0 -168px; 682 | } 683 | 684 | #menu div.menu.episodes li.episode-2 div.button { 685 | background-position : 0 -224px; 686 | } 687 | #menu div.menu.episodes li.active.episode-2 div.button { 688 | background-position : 0 -280px; 689 | } 690 | 691 | 692 | 693 | #menu div.menu.levels li div.button { 694 | width : 256px; 695 | margin-bottom : 16px; 696 | background-image : url(art/menuitems_levels.png); 697 | } 698 | 699 | #menu li.level-0 div.button { 700 | background-position : 0 0; 701 | } 702 | #menu li.active.level-0 div.button { 703 | background-position : -256px 0; 704 | } 705 | 706 | #menu li.level-1 div.button { 707 | background-position : 0 -32px; 708 | } 709 | #menu li.active.level-1 div.button { 710 | background-position : -256px -32px; 711 | } 712 | 713 | #menu li.level-2 div.button { 714 | background-position : 0 -64px; 715 | } 716 | #menu li.active.level-2 div.button { 717 | background-position : -256px -64px; 718 | } 719 | 720 | #menu li.level-3 div.button { 721 | background-position : 0 -96px; 722 | } 723 | #menu li.active.level-3 div.button { 724 | background-position : -256px -96px; 725 | } 726 | 727 | #menu li.level-4 div.button { 728 | background-position : 0 -128px; 729 | } 730 | #menu li.active.level-4 div.button { 731 | background-position : -256px -128px; 732 | } 733 | 734 | #menu li.level-5 div.button { 735 | background-position : 0 -160px; 736 | } 737 | #menu li.active.level-5 div.button { 738 | background-position : -256px -160px; 739 | } 740 | 741 | #menu li.level-6 div.button { 742 | background-position : 0 -192px; 743 | } 744 | #menu li.active.level-6 div.button { 745 | background-position : -256px -192px; 746 | } 747 | 748 | #menu li.level-7 div.button { 749 | background-position : 0 -224px; 750 | } 751 | #menu li.active.level-7 div.button { 752 | background-position : -256px -224px; 753 | } 754 | 755 | #menu li.level-8 div.button{ 756 | background-position : 0 -256px; 757 | } 758 | #menu li.active.level-8 div.button { 759 | background-position : -256px -256px; 760 | } 761 | 762 | #menu li.level-9 div.button { 763 | background-position : 0 -288px; 764 | } 765 | #menu li.active.level-9 div.button { 766 | background-position : -256px -288px; 767 | } 768 | 769 | /* menu toggle light */ 770 | 771 | #menu div.light { 772 | width : 42px; 773 | height : 16px; 774 | margin-left : -48px; 775 | margin-top : 4px; 776 | overflow : hidden; 777 | display : inline-block; 778 | background-image : url(art/menulight.png); 779 | } 780 | 781 | #menu div.light.on { 782 | background-position : 0 24px; 783 | } 784 | 785 | /* menu selector gun */ 786 | 787 | #menu ul.selector li.active::before { 788 | display : block; 789 | width : 46px; 790 | height : 24px; 791 | position : absolute; 792 | left : -50px; 793 | content : ""; 794 | background-image : url(art/menuselector.png); 795 | } 796 | 797 | 798 | #menu div.menu.control ul.selector li.active::before { 799 | left : -100px; 800 | } 801 | 802 | 803 | /* customize keys menu */ 804 | 805 | #menu div.menu.customize ul.selector li.active::before { 806 | left : -96px; 807 | } 808 | #menu div.menu.customize li div.button { 809 | margin-bottom : 28px; 810 | background : none; 811 | } 812 | 813 | #menu div.menu.customize li div.button span { 814 | position : relative; 815 | display : inline-block; 816 | width : 122px; 817 | height : 28px; 818 | background-image : url(art/control_keys.png); 819 | background-position : 0 -128px; 820 | margin-right : -6px; 821 | } 822 | #menu div.menu.customize li div.button span.k1 { 823 | } 824 | #menu div.menu.customize li div.button span.k2 { 825 | } 826 | #menu div.menu.customize li div.button span.k3 { 827 | } 828 | #menu div.menu.customize li div.button span.k4 { 829 | } 830 | 831 | #menu div.menu.customize li div.button span:hover { 832 | 833 | } 834 | 835 | /* skill menu face */ 836 | 837 | #menu div.menu.skill div.face { 838 | width : 48px; 839 | height : 64px; 840 | left : 460px; 841 | top : 210px; 842 | position : absolute; 843 | background-image : url(art/skillfaces.png); 844 | } 845 | 846 | #menu div.menu.skill div.face.gd_baby { 847 | background-position : 0 0; 848 | } 849 | #menu div.menu.skill div.face.gd_easy { 850 | background-position : -48px 0; 851 | } 852 | #menu div.menu.skill div.face.gd_medium { 853 | background-position : -96px 0; 854 | } 855 | #menu div.menu.skill div.face.gd_hard { 856 | background-position : -144px 0; 857 | } 858 | 859 | 860 | /* menu confirm box */ 861 | 862 | #menu .message { 863 | position : absolute; 864 | z-index : 1000; 865 | left : 0; 866 | top : 0; 867 | width : 100%; 868 | height : 100%; 869 | display : none; 870 | } 871 | 872 | #menu .message.confirm-newgame div.box { 873 | position : absolute; 874 | width : 460px; 875 | height : 100px; 876 | left : 50%; 877 | top : 50%; 878 | margin-left : -230px; 879 | margin-top : -50px; 880 | overflow : hidden; 881 | background-image : url(art/confirm_newgame.png); 882 | } 883 | 884 | #menu .message.confirm-newgame div.box.blink { 885 | background-position : 0 100px; 886 | } 887 | 888 | -------------------------------------------------------------------------------- /wolf3d.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Wolfenstein 3D 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 29 | 113 | 114 |
115 | 116 | 117 |
118 |
119 | 120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | 130 |
131 | 132 |
133 | 134 |
135 |
136 |
137 |
138 | 139 |
140 | 141 |
142 |
143 |
144 |
145 | 146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | 155 |
156 |
157 |
158 |
159 |
160 |
161 | 162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | 179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | 195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 | 206 | 207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 | 231 | 232 | --------------------------------------------------------------------------------