commit e0b653888de40ece0beb7ef73e177ffe431f1a62 Author: Brian Harris Date: Thu May 16 11:34:31 2013 -0500 Wolfenstein 3D browser version This is the code for the browser version of Wolfenstein 3D which is playable on http://www.wolfenstein.com/game_NA.php diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..b3f64f0 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,345 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..a38bc3c --- /dev/null +++ b/README.txt @@ -0,0 +1,22 @@ +WOLF3D Browser Version GPL source release +=============================================== + +This file contains the following sections: + +GENERAL NOTES +LICENSE + +GENERAL NOTES +============= + +WOLF3D Browser Version is a free release, and can be downloaded from +https://github.com/id-Software/wolf3d-browser + +This source release does not contain any game data, the game data remains subject to the original EULA and applicable law. + + +LICENSE +======= + +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. + diff --git a/index.html b/index.html new file mode 100644 index 0000000..324f7f8 --- /dev/null +++ b/index.html @@ -0,0 +1,64 @@ + + + + + + Test Page + + + + + + + + + + + \ No newline at end of file diff --git a/js/actorai.js b/js/actorai.js new file mode 100644 index 0000000..a1d3b4e --- /dev/null +++ b/js/actorai.js @@ -0,0 +1,562 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + + +/** + * @namespace + * @description Artificial intelligence + */ +Wolf.ActorAI = (function() { + + var dsounds = [ + "sfx/025.wav", + "sfx/026.wav", + "sfx/086.wav", + "sfx/088.wav", + "sfx/105.wav", + "sfx/107.wav", + "sfx/109.wav" + ]; + + /** + * @description Initiate death scream sound effect. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + */ + function deathScream(self, game) { + var pos = game.player.position; + + switch (self.type) { + case Wolf.en_mutant: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/037.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_guard: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, dsounds[Wolf.Random.rnd() % 6], 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_officer: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/074.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_ss: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/046.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_dog: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/035.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_boss: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/019.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_schabbs: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/061.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_fake: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/069.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_mecha: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/084.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_hitler: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/044.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_gretel: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/115.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_gift: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/091.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_fat: + Wolf.Sound.startSound(pos, self, 1, Wolf.CHAN_VOICE, "sfx/119.wav", 1, Wolf.ATTN_NORM, 0); + break; + } + } + + /* Hitler */ + + /** + * @description Play Mecha sound. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + */ + function mechaSound(self, game) { + if (game.level.state.areabyplayer[self.areanumber]) { + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/080.wav", 1, Wolf.ATTN_NORM, 0); + } + } + + + /** + * @description Play Slurpie sound. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + */ + function slurpie(self, game) { + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "lsfx/061.wav", 1, Wolf.ATTN_NORM, 0); + } + + + /** + * @description Spawn new actor, when Mecha Hitler is dead. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + */ + function hitlerMorph(self, game) { + var hitpoints = [500, 700, 800, 900], + level = game.level, + hitler; + + hitler = Wolf.Actors.getNewActor(level); + if(!hitler) { + return; + } + + hitler.x = self.x; + hitler.y = self.y; + hitler.distance = self.distance; + hitler.tile.x = self.tile.x; + hitler.tile.y = self.tile.y; + hitler.angle = self.angle; + hitler.dir = self.dir; + hitler.health = hitpoints[game.skill]; + hitler.areanumber = self.areanumber; + hitler.state = Wolf.st_chase1; + hitler.type = Wolf.en_hitler; + hitler.speed = Wolf.SPDPATROL * 5; + hitler.ticcount = 0; + hitler.flags = self.flags | Wolf.FL_SHOOTABLE; + hitler.sprite = Wolf.Sprites.getNewSprite(level); + + } + + /* Angel of Death */ + + var angel_temp = 0; + + /** + * @description Play Angel of Death Breathing sound. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + */ + function breathing(self) { + Wolf.Sound.startSound(null, null, 1, Wolf.CHAN_VOICE, "lsfx/080.wav", 1, Wolf.ATTN_NORM, 0); + } + + + /** + * @description Reset Angel of Death attack counter + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + */ + function startAttack(self) { + angel_temp = 0; + } + + + /** + * @description Angel of Death AI. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + */ + function relaunch(self) { + if (++angel_temp == 3) { + Wolf.Actors.stateChange(self, Wolf.st_pain); + return; + } + + if (Wolf.Random.rnd() & 1) { + Wolf.Actors.stateChange(self, Wolf.st_chase1); + return; + } + } + + /** + * @description Victory - start intermission. + * @memberOf Wolf.ActorAI + */ + function victory(game) { + Wolf.Game.startIntermission(game); + } + + + /** + * @description Entity is dormant state. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + */ + function dormant(self, game) { + var level = game.level, + player = game.player, + deltax, + deltay, + xl, xh, yl, yh, + x, y, n, + moveok = false; + + deltax = self.x - player.position.x; + deltay = self.y - player.position.y; + + if (deltax < -Wolf.MINACTORDIST || deltax > Wolf.MINACTORDIST) { + moveok = true; + } else if(deltay < -Wolf.MINACTORDIST || deltay > Wolf.MINACTORDIST) { + moveok = true; + } + + if (!moveok) { + return; + } + + // moveok: + xl = (self.x - Wolf.MINDIST) >> Wolf.TILESHIFT; + xh = (self.x + Wolf.MINDIST) >> Wolf.TILESHIFT; + yl = (self.y - Wolf.MINDIST) >> Wolf.TILESHIFT; + yh = (self.y + Wolf.MINDIST) >> Wolf.TILESHIFT; + + for(y = yl; y <= yh ; ++y ) { + for(x = xl;x <= xh;++x) { + if (level.tileMap[x][y] & Wolf.SOLID_TILE) { + return; + } + for (n=0;n= Wolf.st_die1) { + continue; + } + if (level.state.guards[n].tile.x == x && level.state.guards[n].tile.y == y) { + return; // another guard in path + } + } + } + } + + self.flags |= Wolf.FL_AMBUSH | Wolf.FL_SHOOTABLE; + self.flags &= ~Wolf.FL_ATTACKMODE; + self.dir = Wolf.Math.dir8_nodir; + Wolf.Actors.stateChange(self, Wolf.st_path1); + } + + + /** + * @description Death cam animation. + * Tthe DeathCam feature isn't implimented, but we want to + * give the animation time to play before declaring victory. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + */ + function startDeathCam(game, self) { + self.playstate = Wolf.ex_complete; + setTimeout(function() { + Wolf.Game.startIntermission(game); + }, 5000); + } + + + /** + * @description Rockets emmit smoke. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} level The level object. + */ + function smoke(self, game) { + var level = game.level, + smokeEnt = Wolf.Actors.getNewActor(level); + + if (!smokeEnt) { + return; + } + + smokeEnt.x = self.x; + smokeEnt.y = self.y; + smokeEnt.tile.x = self.tile.x; + smokeEnt.tile.y = self.tile.y; + smokeEnt.state = Wolf.st_die1; + smokeEnt.type = (self.type == Wolf.en_hrocket) ? Wolf.en_hsmoke : Wolf.en_smoke; + smokeEnt.ticcount = 6; + smokeEnt.flags = Wolf.FL_NEVERMARK; + smokeEnt.sprite = Wolf.Sprites.getNewSprite(level); + } + + + + /** + * @description Puts an actor into attack mode and possibly reverses the direction if the player is behind it. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + */ + function firstSighting(self, game) { + switch (self.type) { + case Wolf.en_guard: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/001.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_officer: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/071.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 5; // go faster when chasing player + break; + + case Wolf.en_mutant: + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_ss: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/015.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 4; // go faster when chasing player + break; + + case Wolf.en_dog: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/002.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 2; // go faster when chasing player + break; + + case Wolf.en_boss: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/017.wav", 1, Wolf.ATTN_NORM, 0); + self.speed = Wolf.SPDPATROL * 3; // go faster when chasing player + break; + + case Wolf.en_gretel: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/112.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_gift: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/096.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_fat: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/102.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_schabbs: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/065.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_fake: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/054.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_mecha: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/040.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 3; // go faster when chasing player + break; + + case Wolf.en_hitler: + Wolf.Sound.startSound(game.player.position, self, 1, Wolf.CHAN_VOICE, "sfx/040.wav", 1, Wolf.ATTN_NORM, 0); + self.speed *= 5; // go faster when chasing player + break; + + case Wolf.en_blinky: + case Wolf.en_clyde: + case Wolf.en_pinky: + case Wolf.en_inky: + self.speed *= 2; // go faster when chasing player + break; + + default: + return; + } + + Wolf.Actors.stateChange(self, Wolf.st_chase1); + + if (self.waitfordoorx) { + self.waitfordoorx = self.waitfordoory = 0; // ignore the door opening command + } + + self.dir = Wolf.Math.dir8_nodir; + self.flags |= Wolf.FL_ATTACKMODE | Wolf.FL_FIRSTATTACK; + } + + + /** + * @description Called when the player succesfully hits an enemy. + * Does damage points to enemy ob, either putting it into a stun frame or killing it. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + * @param {object} player The player object. + * @param {number} damage The number of damage points. + */ + function damageActor(self, game, player, damage) { + player.madenoise = 1; + + // do double damage if shooting a non attack mode actor + if (!(self.flags & Wolf.FL_ATTACKMODE)) { + damage <<= 1; + } + + self.health -= damage; + + if (self.health <= 0) { + killActor(self, game, player); + } else { + if (!(self.flags & Wolf.FL_ATTACKMODE) ) { + firstSighting(self, game); // put into combat mode + } + switch (self.type) { // dogs only have one hit point + case Wolf.en_guard: + case Wolf.en_officer: + case Wolf.en_mutant: + case Wolf.en_ss: + if (self.health & 1) { + Wolf.Actors.stateChange(self, Wolf.st_pain); + } else { + Wolf.Actors.stateChange(self, Wolf.st_pain1); + } + break; + } + } + } + + + /** + * @description Actor has been killed, so give points and spawn powerups. + * @memberOf Wolf.ActorAI + * @param {object} self The enemy actor object. + * @param {object} game The game object. + * @param {object} player The player object. + */ + function killActor(self, game, player) { + var level = game.level, + tilex = self.tile.x = self.x >> Wolf.TILESHIFT; // drop item on center, + tiley = self.tile.y = self.y >> Wolf.TILESHIFT; + + switch (self.type) { + case Wolf.en_guard: + Wolf.Player.givePoints(player, 100); + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_clip2); + break; + + case Wolf.en_officer: + Wolf.Player.givePoints(player, 400); + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_clip2); + break; + + case Wolf.en_mutant: + Wolf.Player.givePoints(player, 700); + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_clip2); + break; + + case Wolf.en_ss: + Wolf.Player.givePoints(player, 500); + if (player.items & Wolf.ITEM_WEAPON_3) { // have a schmeiser? + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_clip2); + } else { + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_machinegun); + } + break; + + case Wolf.en_dog: + Wolf.Player.givePoints(player, 200); + break; + + case Wolf.en_boss: + Wolf.Player.givePoints(player, 5000); + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_key1); + break; + + case Wolf.en_gretel: + Wolf.Player.givePoints(player, 5000); + Wolf.Powerups.spawn(level, tilex, tiley, Wolf.pow_key1); + break; + + case Wolf.en_gift: + Wolf.Player.givePoints(player, 5000); + startDeathCam(game, self); + break; + + case Wolf.en_fat: + Wolf.Player.givePoints(player, 5000); + startDeathCam(game, self); + break; + + case Wolf.en_schabbs: + Wolf.Player.givePoints(player, 5000); + deathScream(self, game); + startDeathCam(game, self); + break; + + case Wolf.en_fake: + Wolf.Player.givePoints(player, 2000); + break; + + case Wolf.en_mecha: + Wolf.Player.givePoints(player, 5000); + break; + + case Wolf.en_hitler: + Wolf.Player.givePoints(player, 5000); + deathScream(self, game); + startDeathCam(game, self); + break; + + } + + Wolf.Actors.stateChange(self, Wolf.st_die1); + + if (++level.state.killedMonsters == level.state.totalMonsters) { + Wolf.Game.notify("You killed the last enemy!"); + } + + self.flags &= ~Wolf.FL_SHOOTABLE; + self.flags |= Wolf.FL_NONMARK; + } + + return { + firstSighting : firstSighting, + damageActor : damageActor, + killActor : killActor, + deathScream : deathScream, + mechaSound : mechaSound, + slurpie : slurpie, + hitlerMorph : hitlerMorph, + breathing : breathing, + startAttack : startAttack, + relaunch : relaunch, + victory : victory, + dormant : dormant, + startDeathCam : startDeathCam, + smoke : smoke + }; + +})(); \ No newline at end of file diff --git a/js/actors.js b/js/actors.js new file mode 100644 index 0000000..98e71ec --- /dev/null +++ b/js/actors.js @@ -0,0 +1,518 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Actors + */ +Wolf.Actors = (function() { + + Wolf.setConsts({ + SPDPATROL : 512, + SPDDOG : 1500, + + FL_SHOOTABLE : 1, + FL_BONUS : 2, + FL_NEVERMARK : 4, + FL_VISABLE : 8, + FL_ATTACKMODE : 16, + FL_FIRSTATTACK : 32, + FL_AMBUSH : 64, + FL_NONMARK : 128, + + MAX_GUARDS : 255, + NUMENEMIES : 31, + NUMSTATES : 34, + + MINACTORDIST : 0x10000 + }); + + Wolf.setConsts({ + en_guard : 0, + en_officer : 1, + en_ss : 2, + en_dog : 3, + en_boss : 4, + en_schabbs : 5, + en_fake : 6, + en_mecha : 7, + en_hitler : 8, + en_mutant : 9, + en_blinky : 10, + en_clyde : 11, + en_pinky : 12, + en_inky : 13, + en_gretel : 14, + en_gift : 15, + en_fat : 16, + // --- Projectiles + en_needle : 17, + en_fire : 18, + en_rocket : 19, + en_smoke : 20, + en_bj : 21, + // --- Spear of destiny! + en_spark : 22, + en_hrocket : 23, + en_hsmoke : 24, + + en_spectre : 25, + en_angel : 26, + en_trans : 27, + en_uber : 28, + en_will : 29, + en_death : 30 + }); + + Wolf.setConsts({ + st_stand : 0, + st_path1 : 1, + st_path1s : 2, + st_path2 : 3, + st_path3 : 4, + st_path3s : 5, + st_path4 : 6, + st_pain : 7, + st_pain1 : 8, + st_shoot1 : 9, + st_shoot2 : 10, + st_shoot3 : 11, + st_shoot4 : 12, + st_shoot5 : 13, + st_shoot6 : 14, + st_shoot7 : 15, + st_shoot8 : 16, + st_shoot9 : 17, + st_chase1 : 18, + st_chase1s : 19, + st_chase2 : 20, + st_chase3 : 21, + st_chase3s : 22, + st_chase4 : 23, + st_die1 : 24, + st_die2 : 25, + st_die3 : 26, + st_die4 : 27, + st_die5 : 28, + st_die6 : 29, + st_die7 : 30, + st_die8 : 31, + st_die9 : 32, + st_dead : 33, + st_remove : 34 + }); + + var add8dir = [4, 5, 6, 7, 0, 1, 2, 3, 0], + r_add8dir = [4, 7, 6, 5, 0, 1, 2, 3, 0]; + + /** + * @description Create new actor. + * @memberOf Wolf.Actors + * @param {object} level The level object. + * @returns {object} The new actor object. + */ + function getNewActor(level) { + + if (level.state.numGuards > Wolf.MAX_GUARDS) { + return null; + } + + var actor = { + x : 0, + y : 0, + angle : 0, + type : 0, + health : 0, + max_health : 0, + speed : 0, + ticcount : 0, + temp2 : 0, + distance : 0, + tile : { + x : 0, + y : 0 + }, + areanumber : 0, + waitfordoorx : 0, + waitfordoory : 0, // waiting on this door if non 0 + flags : 0, // FL_SHOOTABLE, etc + state : 0, + dir : 0, + sprite : 0 + }; + level.state.guards[level.state.numGuards++] = actor; + + return actor; + } + + /** + * @description Process a single actor. + * @private + * @param {object} ent The actor object. + * @param {object} level The level object. + * @param {object} player The player object. + * @param {number} tics The number of tics. + * @returns {boolean} False if actor should be removed, otherwise true. + */ + function doGuard(ent, game, tics) { // FIXME: revise! + var think; + + //assert( ent->tilex >= 0 && ent->tilex < 64 ); + //assert( ent->tiley >= 0 && ent->tiley < 64 ); + //assert( ent->dir >= 0 && ent->dir <= 8 ); + + + // ticcounts fire discrete actions separate from think functions + if (ent.ticcount) { + ent.ticcount -= tics; + + while (ent.ticcount <= 0) { + //assert( ent->type >= 0 && ent->type < NUMENEMIES ); + //assert( ent->state >= 0 && ent->state < NUMSTATES ); + + think = Wolf.objstate[ent.type][ent.state].action; // end of state action + if (think) { + think(ent, game, tics); + if (ent.state == Wolf.st_remove) { + return false; + } + } + + ent.state = Wolf.objstate[ent.type][ent.state].next_state; + if (ent.state == Wolf.st_remove) { + return false; + } + + if (!Wolf.objstate[ent.type][ent.state].timeout) { + ent.ticcount = 0; + break; + } + + ent.ticcount += Wolf.objstate[ent.type][ent.state].timeout; + } + } + // + // think + // + //assert( ent->type >= 0 && ent->type < NUMENEMIES ); + //assert( ent->state >= 0 && ent->state < NUMSTATES ); + think = Wolf.objstate[ent.type][ent.state].think; + + if (think) { + think(ent, game, tics); + if (ent.state == Wolf.st_remove) { + return false; + } + } + + return true; + } + + + /** + * @description Changes guard's state to that defined in newState. + * @memberOf Wolf.Actors + * @param {object} ent The actor object. + * @param {number} newState The new state. + */ + function stateChange(ent, newState) { + ent.state = newState; + // assert( ent->type >= 0 && ent->type < NUMENEMIES ); + if (newState == Wolf.st_remove) { + ent.ticcount = 0; + } else { + // assert( ent->state >= 0 && ent->state < NUMSTATES ); + ent.ticcount = Wolf.objstate[ent.type][ent.state].timeout; //0; + } + } + + /** + * @description Process all the enemy actors. + * @memberOf Wolf.Actors + * @param {object} level The level object. + * @param {object} player The player object. + * @param {number} tics The number of tics. + */ + function process(game, tics) { + var level = game.level, + player = game.player, + n, tex, guard, + liveGuards = []; + + for (n = 0 ; n < level.state.numGuards ; ++n ) { + guard = level.state.guards[n]; + + if (!doGuard(guard, game, tics)) { + // remove guard from the game forever! + // remove(game, guards[n--]); + Wolf.Sprites.remove(level, guard.sprite); + level.state.guards[n] = null; + continue; + } + + Wolf.Sprites.setPos(level, guard.sprite, guard.x, guard.y, guard.angle); + + tex = Wolf.objstate[guard.type][guard.state].texture; + + if (Wolf.objstate[guard.type][guard.state].rotate) { + if (guard.type == Wolf.en_rocket || guard.type == Wolf.en_hrocket) { + tex += r_add8dir[Wolf.Math.get8dir( Wolf.Angle.distCW(Wolf.FINE2RAD(player.angle), Wolf.FINE2RAD(guard.angle)))]; + } else { + tex += add8dir[Wolf.Math.get8dir( Wolf.Angle.distCW(Wolf.FINE2RAD(player.angle), Wolf.FINE2RAD(guard.angle)))]; + } + } + Wolf.Sprites.setTex(level, guard.sprite, 0, tex); + } + + for (n = 0 ; n < level.state.numGuards ; ++n ) { + if (level.state.guards[n]) { + liveGuards.push(level.state.guards[n]); + } + } + level.state.guards = liveGuards; + level.state.numGuards = liveGuards.length; + } + + /** + * @description Reset and clear the enemy actors in the level. + * @memberOf Wolf.Actors + * @param {object} level The level object. + */ + function resetGuards(level) { + level.state.guards = []; + level.state.numGuards = 0; + //New = NULL; + } + + /** + * @description Spawn a new enemy actor at the given position. + * @memberOf Wolf.Actors + * @param {object} level The level object. + * @param {number} skill The difficulty level. + * @param {number} which The actor type. + * @param {number} x The x position. + * @param {number} y The y position. + * @param {number} dir The direction. + * @returns {object} The new actor object or null if actor creation failed. + */ + function spawn(level, skill, which, x, y, dir) { + var ent = getNewActor(level); + + if (!ent) { + return null; + } + + ent.x = Wolf.TILE2POS(x); + ent.y = Wolf.TILE2POS(y); + + ent.tile.x = x; + ent.tile.y = y; + + // assert( dir >= 0 && dir <= 4 ); + ent.angle = Wolf.Math.dir4angle[dir]; + ent.dir = Wolf.Math.dir4to8[dir]; + + ent.areanumber = level.areas[x][y]; + + if (ent.areanumber < 0) { + // ambush marker tiles are listed as -3 area + ent.areanumber = 0; + } + + // assert( ent->areanumber >= 0 && ent->areanumber < NUMAREAS ); + ent.type = which; + ent.health = Wolf.starthitpoints[skill][which]; + ent.sprite = Wolf.Sprites.getNewSprite(level); + + return ent; + } + + /** + * @description Spawn a dead guard. + * @memberOf Wolf.Actors + * @param {object} level The level object. + * @param {number} skill The difficulty level. + * @param {number} which The actor type. + * @param {number} x The x position. + * @param {number} y The y position. + */ + function spawnDeadGuard(level, skill, which, x, y) { + var self = spawn(level, skill, which, x, y, Wolf.Math.dir4_nodir); + if (!self) { + return; + } + self.state = Wolf.st_dead; + self.speed = 0; + self.health = 0; + self.ticcount = Wolf.objstate[which][Wolf.st_dead].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_dead].timeout + 1 : 0; + } + + /** + * @description Spawn a patrolling guard. + * @memberOf Wolf.Actors + * @param {object} level The level object. + * @param {number} skill The difficulty level. + * @param {number} which The actor type. + * @param {number} x The x position. + * @param {number} y The y position. + */ + function spawnPatrol(level, skill, which, x, y, dir) { + var self = spawn(level, skill, which, x, y, dir); + if (!self) { + return; + } + + self.state = Wolf.st_path1; + self.speed = (which == Wolf.en_dog) ? Wolf.SPDDOG : Wolf.SPDPATROL; + self.distance = Wolf.TILEGLOBAL; + self.ticcount = Wolf.objstate[which][Wolf.st_path1].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_path1].timeout + 1 : 0; + self.flags |= Wolf.FL_SHOOTABLE; + + level.state.totalMonsters++; + } + + /** + * @description Spawn a standing guard. + * @memberOf Wolf.Actors + * @param {object} level The level object. + * @param {number} skill The difficulty level. + * @param {number} which The actor type. + * @param {number} x The x position. + * @param {number} y The y position. + */ + function spawnStand(level, skill, which, x, y, dir) { + var self = spawn(level, skill, which, x, y, dir); + if (!self) { + return; + } + + self.state = Wolf.st_stand; + self.speed = Wolf.SPDPATROL; + self.ticcount = Wolf.objstate[which][Wolf.st_stand].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_stand].timeout + 1 : 0; + self.flags |= Wolf.FL_SHOOTABLE; + + if (level.tileMap[x][y] & Wolf.AMBUSH_TILE) { + self.flags |= Wolf.FL_AMBUSH; + } + + level.state.totalMonsters++; + } + + function spawnBoss(level, skill, which, x, y) { + var self, + face; + + switch (which) { + case Wolf.en_boss: + case Wolf.en_schabbs: + case Wolf.en_fat: + case Wolf.en_hitler: + face = Wolf.Math.dir4_south; + break; + + case Wolf.en_fake: + case Wolf.en_gretel: + case Wolf.en_gift: + face = Wolf.Math.dir4_north; + break; + + case Wolf.en_trans: + case Wolf.en_uber: + case Wolf.en_will: + case Wolf.en_death: + case Wolf.en_angel: + case Wolf.en_spectre: + face = Wolf.Math.dir4_nodir; + break; + + default: + face = Wolf.Math.dir4_nodir; + break; + } + + self = spawn(level, skill, which, x, y, face); + if (!self) { + return; + } + + self.state = which == Wolf.en_spectre ? Wolf.st_path1 : Wolf.st_stand; + self.speed = Wolf.SPDPATROL; + self.health = Wolf.starthitpoints[skill][which]; + self.ticcount = Wolf.objstate[which][Wolf.st_stand].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_stand].timeout + 1 : 0; + self.flags |= Wolf.FL_SHOOTABLE | Wolf.FL_AMBUSH; + + level.state.totalMonsters++; + } + + + function spawnGhosts(level, skill, which, x, y) { + var self = spawn(level, skill, which, x, y, Wolf.Math.dir4_nodir); + if (!self) { + return; + } + + self.state = Wolf.st_chase1; + self.speed = Wolf.SPDPATROL * 3; + self.health = Wolf.starthitpoints[skill][which]; + self.ticcount = Wolf.objstate[which][Wolf.st_chase1].timeout ? Wolf.Random.rnd() % Wolf.objstate[which][Wolf.st_chase1].timeout + 1: 0; + self.flags |= Wolf.FL_AMBUSH; + + level.state.totalMonsters++; + } + + function spawnBJVictory(player, level, skill) { + var x = Wolf.POS2TILE(player.position.x), + y = Wolf.POS2TILE(player.position.y), + bj = spawn(level, skill, Wolf.en_bj, x, y + 1, Wolf.Math.dir4_north); + + if (!bj) { + return; + } + + bj.x = player.position.x; + bj.y = player.position.y; + bj.state = Wolf.st_path1; + bj.speed = Wolf.BJRUNSPEED; + bj.flags = Wolf.FL_NONMARK; // FL_NEVERMARK; + bj.temp2 = 6; + bj.ticcount = 1; + } + + return { + process : process, + resetGuards : resetGuards, + getNewActor : getNewActor, + spawn : spawn, + spawnDeadGuard : spawnDeadGuard, + spawnPatrol : spawnPatrol, + spawnStand : spawnStand, + spawnBoss : spawnBoss, + spawnGhosts : spawnGhosts, + spawnBJVictory : spawnBJVictory, + stateChange : stateChange + }; + +})(); diff --git a/js/actstat.js b/js/actstat.js new file mode 100644 index 0000000..add6f49 --- /dev/null +++ b/js/actstat.js @@ -0,0 +1,1631 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +(function() { + var ST_INFO_NULL = [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead] + + /* + 1-if object can be rotated, 0 if one sprite for every direction + base object's state texture if rotation is on facing player + after how man frames change state to .next_state + what to do every frame + what to do once per state + next state + */ + + //var objstate[Wolf.NUMENEMIES][Wolf.NUMSTATES] = [ + var objstate = [ + // en_guard, + [ + [ 1, Wolf.SPR_GRD_S_1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand ], // Wolf.st_stand, + + [ 1, Wolf.SPR_GRD_W1_1, 20, Wolf.AI.T_Path, null, Wolf.st_path1s ], // Wolf.st_path1, + [ 1, Wolf.SPR_GRD_W1_1, 5, null, null, Wolf.st_path2 ], // Wolf.st_path1s, + [ 1, Wolf.SPR_GRD_W2_1, 15, Wolf.AI.T_Path, null, Wolf.st_path3 ], // Wolf.st_path2, + [ 1, Wolf.SPR_GRD_W3_1, 20, Wolf.AI.T_Path, null, Wolf.st_path3s ], // Wolf.st_path3, + [ 1, Wolf.SPR_GRD_W3_1, 5, null, null, Wolf.st_path4 ], // Wolf.st_path3s, + [ 1, Wolf.SPR_GRD_W4_1, 15, Wolf.AI.T_Path, null, Wolf.st_path1 ], // Wolf.st_path4, + + [ 0, Wolf.SPR_GRD_PAIN_1, 10, null, null, Wolf.st_chase1],// Wolf.st_pain, + [ 0, Wolf.SPR_GRD_PAIN_2, 10, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [ 0, Wolf.SPR_GRD_SHOOT1, 20, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [ 0, Wolf.SPR_GRD_SHOOT2, 20, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [ 0, Wolf.SPR_GRD_SHOOT3, 20, null, null, Wolf.st_chase1],// Wolf.st_shoot3, + + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1 ], // Wolf.st_shoot4, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1 ], // Wolf.st_shoot5, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1 ], // Wolf.st_shoot6, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1 ], // Wolf.st_shoot7, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1 ], // Wolf.st_shoot8, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1 ], // Wolf.st_shoot9, + + [ 1, Wolf.SPR_GRD_W1_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s ], // Wolf.st_chase1, + [ 1, Wolf.SPR_GRD_W1_1, 3, null, null, Wolf.st_chase2 ], // Wolf.st_chase1s, + [ 1, Wolf.SPR_GRD_W2_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3 ], // Wolf.st_chase2, + [ 1, Wolf.SPR_GRD_W3_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s ], // Wolf.st_chase3, + [ 1, Wolf.SPR_GRD_W3_1, 3, null, null, Wolf.st_chase4 ], // Wolf.st_chase3s, + [ 1, Wolf.SPR_GRD_W4_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1 ], // Wolf.st_chase4, + + [ 0, Wolf.SPR_GRD_DIE_1, 15, null, Wolf.ActorAI.deathScream, Wolf.st_die2 ], // Wolf.st_die1, + [ 0, Wolf.SPR_GRD_DIE_2, 15, null, null, Wolf.st_die3 ], // Wolf.st_die2, + [ 0, Wolf.SPR_GRD_DIE_3, 15, null, null, Wolf.st_dead ], // Wolf.st_die3, + + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead ], // Wolf.st_die4, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead ], // Wolf.st_die5, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead ], // Wolf.st_die6, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead ], // Wolf.st_die7, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead ], // Wolf.st_die8, + [ 0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead ], // Wolf.st_die9, + + [ 0, Wolf.SPR_GRD_DEAD, 0, null, null, Wolf.st_dead ] // Wolf.st_dead + ], + // en_officer, + [ + [1, Wolf.SPR_OFC_S_1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [1, Wolf.SPR_OFC_W1_1, 20, Wolf.AI.T_Path, null, Wolf.st_path1s],// Wolf.st_path1, + [1, Wolf.SPR_OFC_W1_1, 5, null, null, Wolf.st_path2], // Wolf.st_path1s, + [1, Wolf.SPR_OFC_W2_1, 15, Wolf.AI.T_Path, null, Wolf.st_path3], // Wolf.st_path2, + [1, Wolf.SPR_OFC_W3_1, 20, Wolf.AI.T_Path, null, Wolf.st_path3s],// Wolf.st_path3, + [1, Wolf.SPR_OFC_W3_1, 5, null, null, Wolf.st_path4], // Wolf.st_path3s, + [1, Wolf.SPR_OFC_W4_1, 15, Wolf.AI.T_Path, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_OFC_PAIN_1, 10, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_OFC_PAIN_2, 10, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_OFC_SHOOT1, 6, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_OFC_SHOOT2, 20, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_OFC_SHOOT3, 10, null, null, Wolf.st_chase1],// Wolf.st_shoot3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [1, Wolf.SPR_OFC_W1_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [1, Wolf.SPR_OFC_W1_1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [1, Wolf.SPR_OFC_W2_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [1, Wolf.SPR_OFC_W3_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [1, Wolf.SPR_OFC_W3_1, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [1, Wolf.SPR_OFC_W4_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_OFC_DIE_1, 11, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_OFC_DIE_2, 11, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_OFC_DIE_3, 11, null, null, Wolf.st_dead],// Wolf.st_die3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_OFC_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_ss, + [ + [1, Wolf.SPR_SS_S_1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [1, Wolf.SPR_SS_W1_1, 20, Wolf.AI.T_Path, null, Wolf.st_path1s],// Wolf.st_path1, + [1, Wolf.SPR_SS_W1_1, 5, null, null, Wolf.st_path2], // Wolf.st_path1s, + [1, Wolf.SPR_SS_W2_1, 15, Wolf.AI.T_Path, null, Wolf.st_path3], // Wolf.st_path2, + [1, Wolf.SPR_SS_W3_1, 20, Wolf.AI.T_Path, null, Wolf.st_path3s],// Wolf.st_path3, + [1, Wolf.SPR_SS_W3_1, 5, null, null, Wolf.st_path4], // Wolf.st_path3s, + [1, Wolf.SPR_SS_W4_1, 15, Wolf.AI.T_Path, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_SS_PAIN_1, 10, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_SS_PAIN_2, 10, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_SS_SHOOT1, 20, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_SS_SHOOT2, 20, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_SS_SHOOT3, 10, null, null, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_SS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_SS_SHOOT3, 10, null, null, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_SS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot7],// Wolf.st_shoot6, + [0, Wolf.SPR_SS_SHOOT3, 10, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_SS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_SS_SHOOT3, 10, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [1, Wolf.SPR_SS_W1_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [1, Wolf.SPR_SS_W1_1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [1, Wolf.SPR_SS_W2_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [1, Wolf.SPR_SS_W3_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [1, Wolf.SPR_SS_W3_1, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [1, Wolf.SPR_SS_W4_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_SS_DIE_1, 15, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_SS_DIE_2, 15, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_SS_DIE_3, 15, null, null, Wolf.st_dead],// Wolf.st_die3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_SS_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_dog, + [ + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_stand], // Wolf.st_stand, + + [1, Wolf.SPR_DOG_W1_1, 20, Wolf.AI.T_Path, null, Wolf.st_path1s],// Wolf.st_path1, + [1, Wolf.SPR_DOG_W1_1, 5, null, null, Wolf.st_path2], // Wolf.st_path1s, + [1, Wolf.SPR_DOG_W2_1, 15, Wolf.AI.T_Path, null, Wolf.st_path3], // Wolf.st_path2, + [1, Wolf.SPR_DOG_W3_1, 20, Wolf.AI.T_Path, null, Wolf.st_path3s],// Wolf.st_path3, + [1, Wolf.SPR_DOG_W3_1, 5, null, null, Wolf.st_path4], // Wolf.st_path3s, + [1, Wolf.SPR_DOG_W4_1, 15, Wolf.AI.T_Path, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_DOG_JUMP1, 10, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_DOG_JUMP2, 10, null, Wolf.AI.T_Bite, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_DOG_JUMP3, 10, null, null, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_DOG_JUMP1, 10, null, null, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_DOG_W1_1, 10, null, null, Wolf.st_chase1],// Wolf.st_shoot5, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [1, Wolf.SPR_DOG_W1_1, 10, Wolf.AI.T_DogChase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [1, Wolf.SPR_DOG_W1_1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [1, Wolf.SPR_DOG_W2_1, 8, Wolf.AI.T_DogChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [1, Wolf.SPR_DOG_W3_1, 10, Wolf.AI.T_DogChase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [1, Wolf.SPR_DOG_W3_1, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [1, Wolf.SPR_DOG_W4_1, 8, Wolf.AI.T_DogChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_DOG_DIE_1, 15, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_DOG_DIE_2, 15, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_DOG_DIE_3, 15, null, null, Wolf.st_dead],// Wolf.st_die3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_DOG_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_boss, + [ + [0, Wolf.SPR_BOSS_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_BOSS_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_BOSS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_BOSS_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_BOSS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_BOSS_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_BOSS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot7],// Wolf.st_shoot6, + [0, Wolf.SPR_BOSS_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_BOSS_SHOOT1, 10, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_BOSS_W1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_BOSS_W1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_BOSS_W2, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_BOSS_W3, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_BOSS_W3, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_BOSS_W4, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_BOSS_DIE1, 15, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_BOSS_DIE2, 15, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_BOSS_DIE3, 15, null, null, Wolf.st_dead],// Wolf.st_die3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_BOSS_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_schabbs, + [ + [0, Wolf.SPR_SCHABB_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_SCHABB_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_SCHABB_SHOOT2, 10, null, Wolf.AI.T_Launch, Wolf.st_chase1],// Wolf.st_shoot2, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_SCHABB_W1, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_SCHABB_W1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_SCHABB_W2, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_SCHABB_W3, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_SCHABB_W3, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_SCHABB_W4, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_SCHABB_W1, 10, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_SCHABB_W1, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_SCHABB_DIE1, 10, null, null, Wolf.st_die4],// Wolf.st_die3, + [0, Wolf.SPR_SCHABB_DIE2, 10, null, null, Wolf.st_die5],// Wolf.st_die4, + [0, Wolf.SPR_SCHABB_DIE3, 10, null, null, Wolf.st_dead],// Wolf.st_die5, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_SCHABB_DEAD, 0, null, Wolf.ActorAI.startDeathCam, Wolf.st_dead] // Wolf.st_dead + ], + // en_fake, + [ + [0, Wolf.SPR_FAKE_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot6],// Wolf.st_shoot4, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot7],// Wolf.st_shoot4, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot8],// Wolf.st_shoot4, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, Wolf.AI.T_Launch, Wolf.st_shoot9],// Wolf.st_shoot4, + [0, Wolf.SPR_FAKE_SHOOT, 8, null, null, Wolf.st_chase1],// Wolf.st_shoot4, + + [0, Wolf.SPR_FAKE_W1, 10, Wolf.AI.T_Fake, null, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_FAKE_W1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_FAKE_W2, 8, Wolf.AI.T_Fake, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_FAKE_W3, 10, Wolf.AI.T_Fake, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_FAKE_W3, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_FAKE_W4, 8, Wolf.AI.T_Fake, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_FAKE_DIE1, 10, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_FAKE_DIE2, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_FAKE_DIE3, 10, null, null, Wolf.st_die4],// Wolf.st_die3, + [0, Wolf.SPR_FAKE_DIE4, 10, null, null, Wolf.st_die5],// Wolf.st_die4, + [0, Wolf.SPR_FAKE_DIE5, 10, null, null, Wolf.st_dead],// Wolf.st_die5, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_FAKE_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_hitler, (mecha) + [ + [0, Wolf.SPR_MECHA_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_MECHA_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_MECHA_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_MECHA_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_MECHA_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_MECHA_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_MECHA_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_chase1],// Wolf.st_shoot6, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_MECHA_W1, 10, Wolf.AI.T_Chase, Wolf.ActorAI.mechaSound, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_MECHA_W1, 6, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_MECHA_W2, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_MECHA_W3, 10, Wolf.AI.T_Chase, Wolf.ActorAI.mechaSound, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_MECHA_W3, 6, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_MECHA_W4, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_MECHA_DIE1, 10, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_MECHA_DIE2, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_MECHA_DIE3, 10, null, Wolf.ActorAI.hitlerMorph, Wolf.st_dead],// Wolf.st_die3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_MECHA_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_hitler, + [ + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_HITLER_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_HITLER_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_HITLER_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_HITLER_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_HITLER_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_HITLER_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_chase1],// Wolf.st_shoot6, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_HITLER_W1, 6, Wolf.AI.T_Chase, null, Wolf.st_chase1s], // Wolf.st_chase1, + [0, Wolf.SPR_HITLER_W1, 4, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_HITLER_W2, 2, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_HITLER_W3, 6, Wolf.AI.T_Chase, null, Wolf.st_chase3s], // Wolf.st_chase3, + [0, Wolf.SPR_HITLER_W3, 4, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_HITLER_W4, 2, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_HITLER_W1, 1, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_HITLER_W1, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_HITLER_DIE1, 10, null, null, Wolf.st_die4],// Wolf.st_die3, + [0, Wolf.SPR_HITLER_DIE2, 10, null, null, Wolf.st_die5],// Wolf.st_die4, + [0, Wolf.SPR_HITLER_DIE3, 10, null, null, Wolf.st_die6],// Wolf.st_die5, + [0, Wolf.SPR_HITLER_DIE4, 10, null, null, Wolf.st_die7],// Wolf.st_die6, + [0, Wolf.SPR_HITLER_DIE5, 10, null, null, Wolf.st_die8],// Wolf.st_die7, + [0, Wolf.SPR_HITLER_DIE6, 10, null, null, Wolf.st_die9],// Wolf.st_die8, + [0, Wolf.SPR_HITLER_DIE7, 10, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_HITLER_DEAD, 0, null, Wolf.ActorAI.startDeathCam, Wolf.st_dead] // Wolf.st_dead + ], + // en_mutant, + [ + [1, Wolf.SPR_MUT_S_1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [1, Wolf.SPR_MUT_W1_1, 20, Wolf.AI.T_Path, null, Wolf.st_path1s],// Wolf.st_path1, + [1, Wolf.SPR_MUT_W1_1, 5, null , null, Wolf.st_path2], // Wolf.st_path1s, + [1, Wolf.SPR_MUT_W2_1, 15, Wolf.AI.T_Path, null, Wolf.st_path3], // Wolf.st_path2, + [1, Wolf.SPR_MUT_W3_1, 20, Wolf.AI.T_Path, null, Wolf.st_path3s],// Wolf.st_path3, + [1, Wolf.SPR_MUT_W3_1, 5, null , null, Wolf.st_path4], // Wolf.st_path3s, + [1, Wolf.SPR_MUT_W4_1, 15, Wolf.AI.T_Path, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_MUT_PAIN_1, 10, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_MUT_PAIN_2, 10, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_MUT_SHOOT1, 6, null, Wolf.AI.T_Shoot, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_MUT_SHOOT2, 20, null, null, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_MUT_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4], // Wolf.st_shoot3, + [0, Wolf.SPR_MUT_SHOOT4, 20, null, null, Wolf.st_chase1], // Wolf.st_shoot4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [1, Wolf.SPR_MUT_W1_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [1, Wolf.SPR_MUT_W1_1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [1, Wolf.SPR_MUT_W2_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [1, Wolf.SPR_MUT_W3_1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [1, Wolf.SPR_MUT_W3_1, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [1, Wolf.SPR_MUT_W4_1, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_MUT_DIE_1, 7, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_MUT_DIE_2, 7, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_MUT_DIE_3, 7, null, null, Wolf.st_die4],// Wolf.st_die3, + [0, Wolf.SPR_MUT_DIE_4, 7, null, null, Wolf.st_dead],// Wolf.st_die4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_MUT_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_blinky, + [ + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_BLINKY_W1, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase2],// Wolf.st_chase1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_BLINKY_W2, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase1],// Wolf.st_chase2, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_dead],// Wolf.st_die3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_clyde, + [ + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_CLYDE_W1, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase2],// Wolf.st_chase1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_CLYDE_W2, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase1],// Wolf.st_chase2, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_dead],// Wolf.st_die3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_pinky, + [ + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_PINKY_W1, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase2],// Wolf.st_chase1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_PINKY_W2, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase1],// Wolf.st_chase2, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_dead],// Wolf.st_die3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_inky, + [ + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_shoot9],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_INKY_W1, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase2],// Wolf.st_chase1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_INKY_W2, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase1],// Wolf.st_chase2, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_DEMO, 10, null, null, Wolf.st_dead],// Wolf.st_die3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_gretel, + [ + [0, Wolf.SPR_GRETEL_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_GRETEL_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_GRETEL_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_GRETEL_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_GRETEL_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_GRETEL_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_GRETEL_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot7],// Wolf.st_shoot6, + [0, Wolf.SPR_GRETEL_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot8],// Wolf.st_shoot7, + [0, Wolf.SPR_GRETEL_SHOOT1, 10, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_GRETEL_W1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_GRETEL_W1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_GRETEL_W2, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_GRETEL_W3, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_GRETEL_W3, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_GRETEL_W4, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_GRETEL_DIE1, 15, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_GRETEL_DIE2, 15, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_GRETEL_DIE3, 15, null, null, Wolf.st_dead],// Wolf.st_die3, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_GRETEL_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_gift, + [ + [0, Wolf.SPR_GIFT_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_GIFT_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_GIFT_SHOOT2, 10, null, Wolf.AI.T_Launch, Wolf.st_chase1],// Wolf.st_shoot2, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot4, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot5, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_GIFT_W1, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_GIFT_W1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_GIFT_W2, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_GIFT_W3, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_GIFT_W3, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_GIFT_W4, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_GIFT_W1, 10, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_GIFT_W1, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_GIFT_DIE1, 10, null, null, Wolf.st_die4],// Wolf.st_die3, + [0, Wolf.SPR_GIFT_DIE2, 10, null, null, Wolf.st_die5],// Wolf.st_die4, + [0, Wolf.SPR_GIFT_DIE3, 10, null, null, Wolf.st_dead],// Wolf.st_die5, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_GIFT_DEAD, 0, null, Wolf.ActorAI.startDeathCam, Wolf.st_dead] // Wolf.st_dead + ], + // en_fat, + [ + [0, Wolf.SPR_FAT_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1s],// Wolf.st_path1, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path3s],// Wolf.st_path3, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_path1], // Wolf.st_path4, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_pain1, + + [0, Wolf.SPR_FAT_SHOOT1, 30, null, null, Wolf.st_shoot2],// Wolf.st_shoot1, + [0, Wolf.SPR_FAT_SHOOT2, 10, null, Wolf.AI.T_Launch, Wolf.st_shoot3],// Wolf.st_shoot2, + [0, Wolf.SPR_FAT_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4],// Wolf.st_shoot3, + [0, Wolf.SPR_FAT_SHOOT4, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5],// Wolf.st_shoot4, + [0, Wolf.SPR_FAT_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6],// Wolf.st_shoot5, + [0, Wolf.SPR_FAT_SHOOT4, 10, null, Wolf.AI.T_Shoot, Wolf.st_chase1],// Wolf.st_shoot6, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_chase1],// Wolf.st_shoot9, + + [0, Wolf.SPR_FAT_W1, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase1s],// Wolf.st_chase1, + [0, Wolf.SPR_FAT_W1, 3, null , null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_FAT_W2, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_FAT_W3, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase3s],// Wolf.st_chase3, + [0, Wolf.SPR_FAT_W3, 3, null , null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_FAT_W4, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_FAT_W1, 10, null, Wolf.ActorAI.deathScream, Wolf.st_die2],// Wolf.st_die1, + [0, Wolf.SPR_FAT_W1, 10, null, null, Wolf.st_die3],// Wolf.st_die2, + [0, Wolf.SPR_FAT_DIE1, 10, null, null, Wolf.st_die4],// Wolf.st_die3, + [0, Wolf.SPR_FAT_DIE2, 10, null, null, Wolf.st_die5],// Wolf.st_die4, + [0, Wolf.SPR_FAT_DIE3, 10, null, null, Wolf.st_dead],// Wolf.st_die5, + + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die6, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die7, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die8, + [0, Wolf.SPR_DEMO, 0, null, null, Wolf.st_dead],// Wolf.st_die9, + + [0, Wolf.SPR_FAT_DEAD, 0, null, Wolf.ActorAI.startDeathCam, Wolf.st_dead] // Wolf.st_dead + ], + // --- Projectiles + // en_needle, + [ + ST_INFO_NULL, // Wolf.st_stand, + + [0, Wolf.SPR_HYPO1, 6, Wolf.AI.T_Projectile, null, Wolf.st_path2], // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + [0, Wolf.SPR_HYPO2, 6, Wolf.AI.T_Projectile, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_HYPO3, 6, Wolf.AI.T_Projectile, null, Wolf.st_path4], // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + [0, Wolf.SPR_HYPO4, 6, Wolf.AI.T_Projectile, null, Wolf.st_path1], // Wolf.st_path4, + + ST_INFO_NULL,// Wolf.st_pain, + ST_INFO_NULL,// Wolf.st_pain1, + + ST_INFO_NULL,// Wolf.st_shoot1, + ST_INFO_NULL,// Wolf.st_shoot2, + ST_INFO_NULL,// Wolf.st_shoot3, + ST_INFO_NULL,// Wolf.st_shoot4, + ST_INFO_NULL,// Wolf.st_shoot5, + ST_INFO_NULL,// Wolf.st_shoot6, + + ST_INFO_NULL,// Wolf.st_shoot7, + ST_INFO_NULL,// Wolf.st_shoot8, + ST_INFO_NULL,// Wolf.st_shoot9, + + ST_INFO_NULL,// Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL,// Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + ST_INFO_NULL, // Wolf.st_die1, + ST_INFO_NULL, // Wolf.st_die2, + ST_INFO_NULL, // Wolf.st_die3, + ST_INFO_NULL,// Wolf.st_die4, + ST_INFO_NULL,// Wolf.st_die5, + + ST_INFO_NULL,// Wolf.st_die6, + ST_INFO_NULL,// Wolf.st_die7, + ST_INFO_NULL,// Wolf.st_die8, + ST_INFO_NULL,// Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_fire, + [ + ST_INFO_NULL, // Wolf.st_stand, + + [0, Wolf.SPR_FIRE1, 6, null, Wolf.AI.T_Projectile, Wolf.st_path2], // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + [0, Wolf.SPR_FIRE2, 6, null, Wolf.AI.T_Projectile, Wolf.st_path1], // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL,// Wolf.st_pain, + ST_INFO_NULL,// Wolf.st_pain1, + + ST_INFO_NULL,// Wolf.st_shoot1, + ST_INFO_NULL,// Wolf.st_shoot2, + ST_INFO_NULL,// Wolf.st_shoot3, + ST_INFO_NULL,// Wolf.st_shoot4, + ST_INFO_NULL,// Wolf.st_shoot5, + ST_INFO_NULL,// Wolf.st_shoot6, + + ST_INFO_NULL,// Wolf.st_shoot7, + ST_INFO_NULL,// Wolf.st_shoot8, + ST_INFO_NULL,// Wolf.st_shoot9, + + ST_INFO_NULL,// Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL,// Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + ST_INFO_NULL, // Wolf.st_die1, + ST_INFO_NULL, // Wolf.st_die2, + ST_INFO_NULL, // Wolf.st_die3, + ST_INFO_NULL,// Wolf.st_die4, + ST_INFO_NULL,// Wolf.st_die5, + + ST_INFO_NULL,// Wolf.st_die6, + ST_INFO_NULL,// Wolf.st_die7, + ST_INFO_NULL,// Wolf.st_die8, + ST_INFO_NULL,// Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_rocket, + [ + [1, Wolf.SPR_ROCKET_1, 3, Wolf.AI.T_Projectile, Wolf.ActorAI.smoke, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL,// Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL,// Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL,// Wolf.st_pain, + ST_INFO_NULL,// Wolf.st_pain1, + + ST_INFO_NULL,// Wolf.st_shoot1, + ST_INFO_NULL,// Wolf.st_shoot2, + ST_INFO_NULL,// Wolf.st_shoot3, + ST_INFO_NULL,// Wolf.st_shoot4, + ST_INFO_NULL,// Wolf.st_shoot5, + ST_INFO_NULL,// Wolf.st_shoot6, + + ST_INFO_NULL,// Wolf.st_shoot7, + ST_INFO_NULL,// Wolf.st_shoot8, + ST_INFO_NULL,// Wolf.st_shoot9, + + ST_INFO_NULL,// Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL,// Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + [0, Wolf.SPR_BOOM_1, 6, null, null, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_BOOM_2, 6, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_BOOM_3, 6, null, null, Wolf.st_remove], // Wolf.st_die3, + ST_INFO_NULL,// Wolf.st_die4, + ST_INFO_NULL,// Wolf.st_die5, + + ST_INFO_NULL,// Wolf.st_die6, + ST_INFO_NULL,// Wolf.st_die7, + ST_INFO_NULL,// Wolf.st_die8, + ST_INFO_NULL,// Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_smoke, + [ + ST_INFO_NULL, // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + ST_INFO_NULL, // Wolf.st_shoot1, + ST_INFO_NULL, // Wolf.st_shoot2, + ST_INFO_NULL, // Wolf.st_shoot3, + ST_INFO_NULL, // Wolf.st_shoot4, + ST_INFO_NULL, // Wolf.st_shoot5, + ST_INFO_NULL, // Wolf.st_shoot6, + + ST_INFO_NULL, // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + ST_INFO_NULL, // Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL, // Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + [0, Wolf.SPR_SMOKE_1, 3, null, null, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_SMOKE_2, 3, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_SMOKE_3, 3, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_SMOKE_4, 3, null, null, Wolf.st_remove], // Wolf.st_die4, + ST_INFO_NULL, // Wolf.st_die5, + + ST_INFO_NULL, // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_bj, + [ + ST_INFO_NULL, // Wolf.st_stand, + + [0, Wolf.SPR_BJ_W1, 12, Wolf.AI.T_BJRun, null, Wolf.st_path1s], // Wolf.st_path1, + [0, Wolf.SPR_BJ_W1, 3, null, null, Wolf.st_path2], // Wolf.st_path1s, + [0, Wolf.SPR_BJ_W2, 8, Wolf.AI.T_BJRun, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_BJ_W3, 12, Wolf.AI.T_BJRun, null, Wolf.st_path3s], // Wolf.st_path3, + [0, Wolf.SPR_BJ_W3, 3, null, null, Wolf.st_path4], // Wolf.st_path3s, + [0, Wolf.SPR_BJ_W4, 8, Wolf.AI.T_BJRun, null, Wolf.st_path1], // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + [0, Wolf.SPR_BJ_JUMP1, 14, Wolf.AI.T_BJJump, null, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_BJ_JUMP2, 14, Wolf.AI.T_BJJump, Wolf.AI.T_BJYell, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_BJ_JUMP3, 14, Wolf.AI.T_BJJump, null, Wolf.st_shoot4], // Wolf.st_shoot3, + [0, Wolf.SPR_BJ_JUMP4,150, null, Wolf.AI.T_BJDone, Wolf.st_shoot4], // Wolf.st_shoot4, + ST_INFO_NULL, // Wolf.st_shoot5, + ST_INFO_NULL, // Wolf.st_shoot6, + + ST_INFO_NULL, // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + ST_INFO_NULL, // Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL, // Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + ST_INFO_NULL, // Wolf.st_die1, + ST_INFO_NULL, // Wolf.st_die2, + ST_INFO_NULL, // Wolf.st_die3, + ST_INFO_NULL, // Wolf.st_die4, + ST_INFO_NULL, // Wolf.st_die5, + + ST_INFO_NULL, // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + + // --- Spear of destiny! + // en_spark, + [ + ST_INFO_NULL, // Wolf.st_stand, + + [0, Wolf.SPR_SPARK1, 6, Wolf.AI.T_Projectile, null, Wolf.st_path2], // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + [0, Wolf.SPR_SPARK2, 6, Wolf.AI.T_Projectile, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_SPARK3, 6, Wolf.AI.T_Projectile, null, Wolf.st_path4], // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + [0, Wolf.SPR_SPARK4, 6, Wolf.AI.T_Projectile, null, Wolf.st_path1], // Wolf.st_path4, + + ST_INFO_NULL,// Wolf.st_pain, + ST_INFO_NULL,// Wolf.st_pain1, + + ST_INFO_NULL,// Wolf.st_shoot1, + ST_INFO_NULL,// Wolf.st_shoot2, + ST_INFO_NULL,// Wolf.st_shoot3, + ST_INFO_NULL,// Wolf.st_shoot4, + ST_INFO_NULL,// Wolf.st_shoot5, + ST_INFO_NULL,// Wolf.st_shoot6, + + ST_INFO_NULL,// Wolf.st_shoot7, + ST_INFO_NULL,// Wolf.st_shoot8, + ST_INFO_NULL,// Wolf.st_shoot9, + + ST_INFO_NULL,// Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL,// Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + ST_INFO_NULL, // Wolf.st_die1, + ST_INFO_NULL, // Wolf.st_die2, + ST_INFO_NULL, // Wolf.st_die3, + ST_INFO_NULL,// Wolf.st_die4, + ST_INFO_NULL,// Wolf.st_die5, + + ST_INFO_NULL,// Wolf.st_die6, + ST_INFO_NULL,// Wolf.st_die7, + ST_INFO_NULL,// Wolf.st_die8, + ST_INFO_NULL,// Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_hrocket, + [ + [1, Wolf.SPR_HROCKET_1, 3, Wolf.AI.T_Projectile, Wolf.ActorAI.smoke, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL,// Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL,// Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL,// Wolf.st_pain, + ST_INFO_NULL,// Wolf.st_pain1, + + ST_INFO_NULL,// Wolf.st_shoot1, + ST_INFO_NULL,// Wolf.st_shoot2, + ST_INFO_NULL,// Wolf.st_shoot3, + ST_INFO_NULL,// Wolf.st_shoot4, + ST_INFO_NULL,// Wolf.st_shoot5, + ST_INFO_NULL,// Wolf.st_shoot6, + + ST_INFO_NULL,// Wolf.st_shoot7, + ST_INFO_NULL,// Wolf.st_shoot8, + ST_INFO_NULL,// Wolf.st_shoot9, + + ST_INFO_NULL,// Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL,// Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + [0, Wolf.SPR_HBOOM_1, 6, null, null, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_HBOOM_2, 6, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_HBOOM_3, 6, null, null, Wolf.st_remove], // Wolf.st_die3, + ST_INFO_NULL,// Wolf.st_die4, + ST_INFO_NULL,// Wolf.st_die5, + + ST_INFO_NULL,// Wolf.st_die6, + ST_INFO_NULL,// Wolf.st_die7, + ST_INFO_NULL,// Wolf.st_die8, + ST_INFO_NULL,// Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_hsmoke, + [ + ST_INFO_NULL, // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + ST_INFO_NULL, // Wolf.st_shoot1, + ST_INFO_NULL, // Wolf.st_shoot2, + ST_INFO_NULL, // Wolf.st_shoot3, + ST_INFO_NULL, // Wolf.st_shoot4, + ST_INFO_NULL, // Wolf.st_shoot5, + ST_INFO_NULL, // Wolf.st_shoot6, + + ST_INFO_NULL, // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + ST_INFO_NULL, // Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + ST_INFO_NULL, // Wolf.st_chase2, + ST_INFO_NULL, // Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + ST_INFO_NULL, // Wolf.st_chase4, + + [0, Wolf.SPR_HSMOKE_1, 3, null, null, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_HSMOKE_2, 3, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_HSMOKE_3, 3, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_HSMOKE_4, 3, null, null, Wolf.st_remove], // Wolf.st_die4, + ST_INFO_NULL, // Wolf.st_die5, + + ST_INFO_NULL, // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_spectre, + [ + ST_INFO_NULL, // Wolf.st_stand, + + [0, Wolf.SPR_SPECTRE_W1, 10, Wolf.AI.T_Stand, null, Wolf.st_path2], // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + [0, Wolf.SPR_SPECTRE_W2, 10, Wolf.AI.T_Stand, null, Wolf.st_path3], // Wolf.st_path2, + [0, Wolf.SPR_SPECTRE_W3, 10, Wolf.AI.T_Stand, null, Wolf.st_path4], // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + [0, Wolf.SPR_SPECTRE_W4, 10, Wolf.AI.T_Stand, null, Wolf.st_path1], // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + ST_INFO_NULL, // Wolf.st_shoot1, + ST_INFO_NULL, // Wolf.st_shoot2, + ST_INFO_NULL, // Wolf.st_shoot3, + ST_INFO_NULL, // Wolf.st_shoot4, + ST_INFO_NULL, // Wolf.st_shoot5, + ST_INFO_NULL, // Wolf.st_shoot6, + + ST_INFO_NULL, // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + [0, Wolf.SPR_SPECTRE_W1, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase2], // Wolf.st_chase1, + ST_INFO_NULL, // Wolf.st_chase1s, + [0, Wolf.SPR_SPECTRE_W2, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_SPECTRE_W3, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase4], // Wolf.st_chase3, + ST_INFO_NULL, // Wolf.st_chase3s, + [0, Wolf.SPR_SPECTRE_W4, 10, Wolf.AI.T_Ghosts, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_SPECTRE_F1, 10, null, null, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_SPECTRE_F2, 10, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_SPECTRE_F3, 10, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_SPECTRE_F4, 300, null, null, Wolf.st_die5], // Wolf.st_die4, + [0, Wolf.SPR_SPECTRE_F4, 10, null, Wolf.ActorAI.dormant, Wolf.st_die5], // Wolf.st_die5, + + ST_INFO_NULL, // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + ST_INFO_NULL // Wolf.st_dead + ], + // en_angel, + [ + [0, Wolf.SPR_ANGEL_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + [0, Wolf.SPR_ANGEL_TIRED1, 40, null, Wolf.ActorAI.breathing, Wolf.st_pain1], // Wolf.st_pain, + [0, Wolf.SPR_ANGEL_TIRED2, 40, null, null, Wolf.st_shoot4], // Wolf.st_pain1, + + [0, Wolf.SPR_ANGEL_SHOOT1, 10, null, Wolf.ActorAI.startAttack, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_ANGEL_SHOOT2, 20, null, Wolf.AI.T_Launch, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_ANGEL_SHOOT1, 10, null, Wolf.ActorAI.relaunch, Wolf.st_shoot2], // Wolf.st_shoot3, + + [0, Wolf.SPR_ANGEL_TIRED1, 40, null, Wolf.ActorAI.breathing, Wolf.st_shoot5], // Wolf.st_shoot4, + [0, Wolf.SPR_ANGEL_TIRED2, 40, null, null, Wolf.st_shoot6], // Wolf.st_shoot5, + [0, Wolf.SPR_ANGEL_TIRED1, 40, null, Wolf.ActorAI.breathing, Wolf.st_shoot7], // Wolf.st_shoot6, + [0, Wolf.SPR_ANGEL_TIRED2, 40, null, null, Wolf.st_shoot8], // Wolf.st_shoot7, + [0, Wolf.SPR_ANGEL_TIRED1, 40, null, Wolf.ActorAI.breathing, Wolf.st_chase1], // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + [0, Wolf.SPR_ANGEL_W1, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase1s], // Wolf.st_chase1, + [0, Wolf.SPR_ANGEL_W1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_ANGEL_W2, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_ANGEL_W3, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase3s], // Wolf.st_chase3, + [0, Wolf.SPR_ANGEL_W3, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_ANGEL_W4, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_ANGEL_W1, 1, null, Wolf.ActorAI.deathScream, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_ANGEL_W1, 1, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_ANGEL_DIE1, 10, null, Wolf.ActorAI.slurpie, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_ANGEL_DIE2, 10, null, null, Wolf.st_die5], // Wolf.st_die4, + [0, Wolf.SPR_ANGEL_DIE3, 10, null, null, Wolf.st_die6], // Wolf.st_die5, + [0, Wolf.SPR_ANGEL_DIE4, 10, null, null, Wolf.st_die7], // Wolf.st_die6, + [0, Wolf.SPR_ANGEL_DIE5, 10, null, null, Wolf.st_die8], // Wolf.st_die7, + [0, Wolf.SPR_ANGEL_DIE6, 10, null, null, Wolf.st_die9], // Wolf.st_die8, + [0, Wolf.SPR_ANGEL_DIE7, 10, null, null, Wolf.st_dead], // Wolf.st_die9, + + [0, Wolf.SPR_ANGEL_DEAD, 130, null, Wolf.ActorAI.victory, Wolf.st_dead] // Wolf.st_dead + ], + // en_trans, + [ + [0, Wolf.SPR_TRANS_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + [0, Wolf.SPR_TRANS_SHOOT1, 30, null, null, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_TRANS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_TRANS_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4], // Wolf.st_shoot3, + [0, Wolf.SPR_TRANS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5], // Wolf.st_shoot4, + [0, Wolf.SPR_TRANS_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6], // Wolf.st_shoot5, + [0, Wolf.SPR_TRANS_SHOOT2, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot7], // Wolf.st_shoot6, + [0, Wolf.SPR_TRANS_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot8], // Wolf.st_shoot7, + [0, Wolf.SPR_TRANS_SHOOT1, 10, null, null, Wolf.st_chase1], // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + [0, Wolf.SPR_TRANS_W1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s], // Wolf.st_chase1, + [0, Wolf.SPR_TRANS_W1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_TRANS_W2, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_TRANS_W3, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s], // Wolf.st_chase3, + [0, Wolf.SPR_TRANS_W3, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_TRANS_W4, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_TRANS_W1, 1, null, Wolf.ActorAI.deathScream, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_TRANS_W1, 1, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_TRANS_DIE1, 15, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_TRANS_DIE2, 15, null, null, Wolf.st_die5], // Wolf.st_die4, + [0, Wolf.SPR_TRANS_DIE3, 15, null, null, Wolf.st_dead], // Wolf.st_die5, + ST_INFO_NULL, // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + [0, Wolf.SPR_TRANS_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_uber, + [ + [0, Wolf.SPR_UBER_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + [0, Wolf.SPR_UBER_SHOOT1, 30, null, null, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_UBER_SHOOT2, 12, null, Wolf.AI.T_UShoot, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_UBER_SHOOT3, 12, null, Wolf.AI.T_UShoot, Wolf.st_shoot4], // Wolf.st_shoot3, + [0, Wolf.SPR_UBER_SHOOT4, 12, null, Wolf.AI.T_UShoot, Wolf.st_shoot5], // Wolf.st_shoot4, + [0, Wolf.SPR_UBER_SHOOT3, 12, null, Wolf.AI.T_UShoot, Wolf.st_shoot6], // Wolf.st_shoot5, + [0, Wolf.SPR_UBER_SHOOT2, 12, null, Wolf.AI.T_UShoot, Wolf.st_shoot7], // Wolf.st_shoot6, + [0, Wolf.SPR_UBER_SHOOT1, 12, null, null, Wolf.st_chase1], // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + [0, Wolf.SPR_UBER_W1, 10, Wolf.AI.T_Chase, null, Wolf.st_chase1s], // Wolf.st_chase1, + [0, Wolf.SPR_UBER_W1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_UBER_W2, 8, Wolf.AI.T_Chase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_UBER_W3, 10, Wolf.AI.T_Chase, null, Wolf.st_chase3s], // Wolf.st_chase3, + [0, Wolf.SPR_UBER_W3, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_UBER_W4, 8, Wolf.AI.T_Chase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_UBER_W1, 1, null, Wolf.ActorAI.deathScream, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_UBER_W1, 1, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_UBER_DIE1, 15, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_UBER_DIE2, 15, null, null, Wolf.st_die5], // Wolf.st_die4, + [0, Wolf.SPR_UBER_DIE3, 15, null, null, Wolf.st_die6], // Wolf.st_die5, + [0, Wolf.SPR_UBER_DIE4, 15, null, null, Wolf.st_dead], // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + [0, Wolf.SPR_UBER_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_will, + [ + [0, Wolf.SPR_WILL_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + [0, Wolf.SPR_WILL_SHOOT1, 30, null, null, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_WILL_SHOOT2, 10, null, Wolf.AI.T_Launch, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_WILL_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4], // Wolf.st_shoot3, + [0, Wolf.SPR_WILL_SHOOT4, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot5], // Wolf.st_shoot4, + [0, Wolf.SPR_WILL_SHOOT3, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot6], // Wolf.st_shoot5, + [0, Wolf.SPR_WILL_SHOOT4, 10, null, Wolf.AI.T_Shoot, Wolf.st_chase1], // Wolf.st_shoot6, + ST_INFO_NULL, // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + [0, Wolf.SPR_WILL_W1, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase1s], // Wolf.st_chase1, + [0, Wolf.SPR_WILL_W1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_WILL_W2, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_WILL_W3, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase3s], // Wolf.st_chase3, + [0, Wolf.SPR_WILL_W3, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_WILL_W4, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_WILL_W1, 1, null, Wolf.ActorAI.deathScream, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_WILL_W1, 10, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_WILL_DIE1, 10, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_WILL_DIE2, 10, null, null, Wolf.st_die5], // Wolf.st_die4, + [0, Wolf.SPR_WILL_DIE3, 10, null, null, Wolf.st_dead], // Wolf.st_die5, + ST_INFO_NULL, // Wolf.st_die6, + ST_INFO_NULL, // Wolf.st_die7, + ST_INFO_NULL, // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + [0, Wolf.SPR_WILL_DEAD, 20, null, null, Wolf.st_dead] // Wolf.st_dead + ], + // en_death + [ + [0, Wolf.SPR_DEATH_W1, 0, Wolf.AI.T_Stand, null, Wolf.st_stand], // Wolf.st_stand, + + ST_INFO_NULL, // Wolf.st_path1, + ST_INFO_NULL, // Wolf.st_path1s, + ST_INFO_NULL, // Wolf.st_path2, + ST_INFO_NULL, // Wolf.st_path3, + ST_INFO_NULL, // Wolf.st_path3s, + ST_INFO_NULL, // Wolf.st_path4, + + ST_INFO_NULL, // Wolf.st_pain, + ST_INFO_NULL, // Wolf.st_pain1, + + [0, Wolf.SPR_DEATH_SHOOT1, 30, null, null, Wolf.st_shoot2], // Wolf.st_shoot1, + [0, Wolf.SPR_DEATH_SHOOT2, 10, null, Wolf.AI.T_Launch, Wolf.st_shoot3], // Wolf.st_shoot2, + [0, Wolf.SPR_DEATH_SHOOT4, 10, null, Wolf.AI.T_Shoot, Wolf.st_shoot4], // Wolf.st_shoot3, + [0, Wolf.SPR_DEATH_SHOOT3, 10, null, Wolf.AI.T_Launch, Wolf.st_shoot5], // Wolf.st_shoot4, + [0, Wolf.SPR_DEATH_SHOOT4, 10, null, Wolf.AI.T_Shoot, Wolf.st_chase1], // Wolf.st_shoot5, + ST_INFO_NULL, // Wolf.st_shoot6, + ST_INFO_NULL, // Wolf.st_shoot7, + ST_INFO_NULL, // Wolf.st_shoot8, + ST_INFO_NULL, // Wolf.st_shoot9, + + [0, Wolf.SPR_DEATH_W1, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase1s], // Wolf.st_chase1, + [0, Wolf.SPR_DEATH_W1, 3, null, null, Wolf.st_chase2], // Wolf.st_chase1s, + [0, Wolf.SPR_DEATH_W2, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase3], // Wolf.st_chase2, + [0, Wolf.SPR_DEATH_W3, 10, Wolf.AI.T_BossChase, null, Wolf.st_chase3s], // Wolf.st_chase3, + [0, Wolf.SPR_DEATH_W3, 3, null, null, Wolf.st_chase4], // Wolf.st_chase3s, + [0, Wolf.SPR_DEATH_W4, 8, Wolf.AI.T_BossChase, null, Wolf.st_chase1], // Wolf.st_chase4, + + [0, Wolf.SPR_DEATH_W1, 1, null, Wolf.ActorAI.deathScream, Wolf.st_die2], // Wolf.st_die1, + [0, Wolf.SPR_DEATH_W1, 10, null, null, Wolf.st_die3], // Wolf.st_die2, + [0, Wolf.SPR_DEATH_DIE1, 10, null, null, Wolf.st_die4], // Wolf.st_die3, + [0, Wolf.SPR_DEATH_DIE2, 10, null, null, Wolf.st_die5], // Wolf.st_die4, + [0, Wolf.SPR_DEATH_DIE3, 10, null, null, Wolf.st_die6], // Wolf.st_die5, + [0, Wolf.SPR_DEATH_DIE4, 10, null, null, Wolf.st_die7], // Wolf.st_die6, + [0, Wolf.SPR_DEATH_DIE5, 10, null, null, Wolf.st_die7], // Wolf.st_die7, + [0, Wolf.SPR_DEATH_DIE6, 10, null, null, Wolf.st_die7], // Wolf.st_die8, + ST_INFO_NULL, // Wolf.st_die9, + + [0, Wolf.SPR_DEATH_DEAD, 0, null, null, Wolf.st_dead] // Wolf.st_dead + ] + ]; + + + // int starthitpoints[ 4 ][ NUMENEMIES ] = + var starthitpoints = [ + // + // BABY MODE + // + [ + 25, // guards + 50, // officer + 100, // SS + 1, // dogs + 850, // Hans + 850, // Schabbs + 200, // fake hitler + 800, // mecha hitler + 500, // hitler + 45, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 850, // Gretel + 850, // Gift + 850, // Fat + // --- Projectiles + 0, // en_needle, + 0, // en_fire, + 0, // en_rocket, + 0, // en_smoke, + 100, // en_bj, + // --- Spear of destiny! + 0, // en_spark, + 0, // en_hrocket, + 0, // en_hsmoke, + + 5, // en_spectre, + 1450, // en_angel, + 850, // en_trans, + 1050, // en_uber, + 950, // en_will, + 1250 // en_death + ], + + // + // DON'T HURT ME MODE + // + [ + 25, // guards + 50, // officer + 100, // SS + 1, // dogs + 950, // Hans + 950, // Schabbs + 300, // fake hitler + 950, // mecha hitler + 700, // hitler + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 950, // Gretel + 950, // Gift + 950, // Fat + // --- Projectiles + 0, // en_needle, + 0, // en_fire, + 0, // en_rocket, + 0, // en_smoke, + 100, // en_bj, + // --- Spear of destiny! + 0, // en_spark, + 0, // en_hrocket, + 0, // en_hsmoke, + + 10, // en_spectre, + 1550, // en_angel, + 950, // en_trans, + 1150, // en_uber, + 1050, // en_will, + 1350 // en_death + ], + + // + // BRING 'EM ON MODE + // + [ + 25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1050, // Hans + 1550, // Schabbs + 400, // fake hitler + 1050, // mecha hitler + 800, // hitler + + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1050, // Gretel + 1050, // Gift + 1050, // Fat + // --- Projectiles + 0, // en_needle, + 0, // en_fire, + 0, // en_rocket, + 0, // en_smoke, + 100, // en_bj, + // --- Spear of destiny! + 0, // en_spark, + 0, // en_hrocket, + 0, // en_hsmoke, + + 15, // en_spectre, + 1650, // en_angel, + 1050, // en_trans, + 1250, // en_uber, + 1150, // en_will, + 1450 // en_death + ], + + // + // DEATH INCARNATE MODE + // + [ + 25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1200, // Hans + 2400, // Schabbs + 500, // fake hitler + 1200, // mecha hitler + 900, // hitler + + 65, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1200, // Gretel + 1200, // Gift + 1200, // Fat + // --- Projectiles + 0, // en_needle, + 0, // en_fire, + 0, // en_rocket, + 0, // en_smoke, + 100, // en_bj, + // --- Spear of destiny! + 0, // en_spark, + 0, // en_hrocket, + 0, // en_hsmoke, + + 25, // en_spectre, + 2000, // en_angel, + 1200, // en_trans, + 1400, // en_uber, + 1300, // en_will, + 1600 // en_death + ] + ]; + + /* + typedef struct + { + char rotate; // 1-if object can be rotated, 0 if one sprite for every direction + int texture; // base object's state texture if rotation is on facing player + int timeout; // after how man ticks change state to .next_state + think_t think; // what to do every frame + think_t action; // what to do once per state + en_state next_state; // next state + } + */ + + // convert to state structs + for (var i=0;i. +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Enemy AI + */ +Wolf.AI = (function() { + + Wolf.setConsts({ + RUNSPEED : 6000, + MINSIGHT : 0x18000 + }); + + + function checkSight(self, game) { + var level = game.level, + player = game.player, + deltax, deltay; + + + // don't bother tracing a line if the area isn't connected to the player's + if (!(self.flags & Wolf.FL_AMBUSH)) { + if (!level.state.areabyplayer[self.areanumber]) { + return false; + } + } + + // if the player is real close, sight is automatic + deltax = player.position.x - self.x; + deltay = player.position.y - self.y; + + if (Math.abs(deltax) < Wolf.MINSIGHT && Math.abs(deltay) < Wolf.MINSIGHT) { + return true; + } + + // see if they are looking in the right direction + switch (self.dir) { + case Wolf.Math.dir8_north: + if (deltay < 0) { + return false; + } + break; + case Wolf.Math.dir8_east: + if (deltax < 0) { + return false; + } + break; + case Wolf.Math.dir8_south: + if (deltay > 0) { + return false; + } + break; + case Wolf.Math.dir8_west: + if (deltax > 0) { + return false; + } + break; + default: + break; + } + + // trace a line to check for blocking tiles (corners) + return Wolf.Level.checkLine(self.x, self.y, player.position.x, player.position.y, level); + } + + + /** + * @description Entity is going to move in a new direction. + * Called, when actor finished previous moving & located in + * the 'center' of the tile. Entity will try walking in direction. + * @private + * @returns {boolean} true if direction is OK, otherwise false. + */ + function changeDir(self, new_dir, level) { + var oldx, + oldy, + newx, + newy, // all it tiles + n, + moveok = false; + + oldx = Wolf.POS2TILE(self.x); + oldy = Wolf.POS2TILE(self.y); + //assert( new_dir >= 0 && new_dir <= 8 ); + newx = oldx + Wolf.Math.dx8dir[new_dir]; + newy = oldy + Wolf.Math.dy8dir[new_dir]; + + if (new_dir & 0x01) { // same as %2 (diagonal dir) + if (level.tileMap[newx][oldy] & Wolf.SOLID_TILE || + level.tileMap[oldx][newy] & Wolf.SOLID_TILE || + level.tileMap[newx][newy] & Wolf.SOLID_TILE) { + return false; + } + + for (n=0; n < level.state.numGuards; ++n) { + if (level.state.guards[n].state >= Wolf.st_die1) { + continue; + } + if (level.state.guards[n].tile.x == newx && level.state.guards[n].tile.y == newy) { + return false; // another guard in path + } + if (level.state.guards[n].tile.x == oldx && level.state.guards[n].tile.y == newy) { + return false; // another guard in path + } + if (level.state.guards[n].tile.x == newx && level.state.guards[n].tile.y == oldy) { + return false; // another guard in path + } + } + } else { // linear dir (E, N, W, S) + if (level.tileMap[newx][newy] & Wolf.SOLID_TILE) { + return false; + } + if (level.tileMap[newx][newy] & Wolf.DOOR_TILE) { + if (self.type == Wolf.en_fake || self.type == Wolf.en_dog) { // they can't open doors + if (level.state.doorMap[newx][newy].action != Wolf.dr_open) { // path is blocked by a closed opened door + return false; + } + } else { + self.waitfordoorx = newx; + self.waitfordoory = newy; + moveok = true; + } + } + if (!moveok) { + for (n = 0; n < level.state.numGuards; ++n) { + if (level.state.guards[n].state >= Wolf.st_die1) { + continue; + } + if (level.state.guards[n].tile.x == newx && level.state.guards[n].tile.y == newy) { + return false; // another guard in path + } + } + } + } + + //moveok: + self.tile.x = newx; + self.tile.y = newy; + + level.tileMap[oldx][oldy] &= ~Wolf.ACTOR_TILE; // update map status + level.tileMap[newx][newy] |= Wolf.ACTOR_TILE; + + if (level.areas[newx][newy] > 0) { + // ambush tiles don't have valid area numbers (-3), so don't change the area if walking over them + self.areanumber = level.areas[newx][newy]; + // assert( self.areanumber >= 0 && self.areanumber < NUMAREAS ); + } + + self.distance = Wolf.TILEGLOBAL; + self.dir = new_dir; + + return true; + } + + /** + * @description Entity is going to turn on a way point. + * @private + */ + function path(self, game) { + var level = game.level; + if (level.tileMap[self.x >> Wolf.TILESHIFT][self.y >> Wolf.TILESHIFT] & Wolf.WAYPOINT_TILE) { + + var tileinfo = level.tileMap[self.x >> Wolf.TILESHIFT][self.y >> Wolf.TILESHIFT]; + + if (tileinfo & Wolf.TILE_IS_E_TURN) { + self.dir = Wolf.Math.dir8_east; + } else if (tileinfo & Wolf.TILE_IS_NE_TURN) { + self.dir = Wolf.Math.dir8_northeast; + } else if (tileinfo & Wolf.TILE_IS_N_TURN) { + self.dir = Wolf.Math.dir8_north; + } else if (tileinfo & Wolf.TILE_IS_NW_TURN) { + self.dir = Wolf.Math.dir8_northwest; + } else if (tileinfo & Wolf.TILE_IS_W_TURN) { + self.dir = Wolf.Math.dir8_west; + } else if (tileinfo & Wolf.TILE_IS_SW_TURN) { + self.dir = Wolf.Math.dir8_southwest; + } else if (tileinfo & Wolf.TILE_IS_S_TURN) { + self.dir = Wolf.Math.dir8_south; + } else if (tileinfo & Wolf.TILE_IS_SE_TURN) { + self.dir = Wolf.Math.dir8_southeast; + } + } + + if (!changeDir(self, self.dir, level)) { + self.dir = Wolf.Math.dir8_nodir; + } + } + + + /** + * @description Called by entities that ARE NOT chasing the player. + * @private + */ + function findTarget(self, game, tics) { + var level = game.level, + player = game.player; + + if (self.temp2) { // count down reaction time + self.temp2 -= tics; + if (self.temp2 > 0) { + return false; + } + self.temp2 = 0; // time to react + } else { + + // check if we can/want to see/hear player + if (player.flags & Wolf.FL_NOTARGET) { + return false; // notarget cheat + } + + // assert( self.areanumber >= 0 && self.areanumber < NUMAREAS ); + if (!(self.flags & Wolf.FL_AMBUSH) && ! level.state.areabyplayer[self.areanumber]) { + return false; + } + + if (!checkSight(self, game)) { // Player is visible - normal behavior + if (self.flags & Wolf.FL_AMBUSH || !player.madenoise) { + return false; + } + } + self.flags &= ~Wolf.FL_AMBUSH; + + + // if we are here we see/hear player!!! + switch (self.type) { + case Wolf.en_guard: + self.temp2 = 1 + Wolf.Random.rnd() / 4; + break; + + case Wolf.en_officer: + self.temp2 = 2; + break; + + case Wolf.en_mutant: + self.temp2 = 1 + Wolf.Random.rnd() / 6; + break; + + case Wolf.en_ss: + self.temp2 = 1 + Wolf.Random.rnd() / 6; + break; + + case Wolf.en_dog: + self.temp2 = 1 + Wolf.Random.rnd() / 8; + break; + + case Wolf.en_boss: + case Wolf.en_schabbs: + case Wolf.en_fake: + case Wolf.en_mecha: + case Wolf.en_hitler: + case Wolf.en_gretel: + case Wolf.en_gift: + case Wolf.en_fat: + case Wolf.en_spectre: + case Wolf.en_angel: + case Wolf.en_trans: + case Wolf.en_uber: + case Wolf.en_will: + case Wolf.en_death: + self.temp2 = 1; + break; + } + + return false; // we are amazed & waiting to understand what to do! + } + + Wolf.ActorAI.firstSighting(self, game); + + return true; + } + + + + /** + * @description As dodge(), but doesn't try to dodge. + * @private + */ + function chase(self, game) { + var level = game.level, + player = game.player, + deltax, + deltay, + d = [], + tdir, olddir, turnaround; + + if (game.player.playstate == Wolf.ex_victory) { + return; + } + + olddir = self.dir; + turnaround = Wolf.Math.opposite8[olddir]; + d[0] = d[1] = Wolf.Math.dir8_nodir; + + deltax = Wolf.POS2TILE(player.position.x) - Wolf.POS2TILE(self.x); + deltay = Wolf.POS2TILE(player.position.y) - Wolf.POS2TILE(self.y); + + if (deltax > 0) { + d[0] = Wolf.Math.dir8_east; + } else if (deltax < 0) { + d[0] = Wolf.Math.dir8_west; + } + + if (deltay > 0) { + d[1] = Wolf.Math.dir8_north; + } else if (deltay < 0) { + d[1] = Wolf.Math.dir8_south; + } + + if (Math.abs(deltay) > Math.abs(deltax)) { + tdir = d[0]; + d[0] = d[1]; + d[1] = tdir; + } // swap d[0] & d[1] + + if (d[0] == turnaround) { + d[0] = Wolf.Math.dir8_nodir; + } + + if (d[1] == turnaround) { + d[1] = Wolf.Math.dir8_nodir; + } + + if (d[0] != Wolf.Math.dir8_nodir) { + if (changeDir(self, d[0], level)) { + return; + } + } + + if (d[1] != Wolf.Math.dir8_nodir) { + if (changeDir(self, d[1], level)) { + return; + } + } + + // there is no direct path to the player, so pick another direction + if (olddir != Wolf.Math.dir8_nodir) { + if (changeDir(self, olddir, level)) { + return; + } + } + + if (Wolf.Random.rnd() > 128) { // randomly determine direction of search + for (tdir = Wolf.Math.dir8_east; tdir <= Wolf.Math.dir8_south; tdir += 2) { // * Revision + if (tdir != turnaround) { + if (changeDir(self, tdir, level)) { + return; + } + } + } + } else { + for (tdir = Wolf.Math.dir8_south; tdir >= Wolf.Math.dir8_east; tdir -= 2) { // * Revision (JDC fix for unsigned enums) + if (tdir != turnaround) { + if (changeDir(self, tdir, level)) { + return; + } + } + } + } + + if (turnaround != Wolf.Math.dir8_nodir) { + if (changeDir(self, turnaround, level)) { + return; + } + } + + self.dir = Wolf.Math.dir8_nodir; // can't move + } + + + /** + * @description Run Away from player. + * @private + */ + function retreat(self, game) { + var level = game.level, + player = game.player, + deltax, + deltay, + d = [], + tdir; + + deltax = Wolf.POS2TILE(player.position.x) - Wolf.POS2TILE(self.x); + deltay = Wolf.POS2TILE(player.position.y) - Wolf.POS2TILE(self.y); + + d[0] = deltax < 0 ? Wolf.Math.dir8_east : Wolf.Math.dir8_west; + d[1] = deltay < 0 ? Wolf.Math.dir8_north : Wolf.Math.dir8_south; + + if (Math.abs(deltay) > Math.abs(deltax)) { + tdir = d[0]; + d[0] = d[1]; + d[1] = tdir; + } // swap d[0] & d[1] + + if (changeDir(self, d[0], level)) { + return; + } + if (changeDir(self, d[1], level)) { + return; + } + + // there is no direct path to the player, so pick another direction + if (Wolf.Random.rnd() > 128) { // randomly determine direction of search + for(tdir = Wolf.Math.dir8_east; tdir <= Wolf.Math.dir8_south; tdir += 2 ) { // * Revision + if (changeDir(self, tdir, level)) { + return; + } + } + } else { + for (tdir = Wolf.Math.dir8_south; tdir >= Wolf.Math.dir8_east; tdir -= 2) { // * Revision (JDC fix for unsigned enums) + if (changeDir(self, tdir, level)) { + return; + } + } + } + + self.dir = Wolf.Math.dir8_nodir; // can't move + } + + + /** + * @description Attempts to choose and initiate a movement for entity + * that sends it towards the player while dodging. + * @private + */ + function dodge(self, game) { + var level = game.level, + player = game.player, + deltax, + deltay, + i, + + dirtry = [], + turnaround, + tdir; + + if (game.player.playstate == Wolf.ex_victory) { + return; + } + + if (self.flags & Wolf.FL_FIRSTATTACK) { + // turning around is only ok the very first time after noticing the player + turnaround = Wolf.Math.dir8_nodir; + self.flags &= ~Wolf.FL_FIRSTATTACK; + } else { + turnaround = Wolf.Math.opposite8[self.dir]; + } + + + deltax = Wolf.POS2TILE(player.position.x) - Wolf.POS2TILE(self.x); + deltay = Wolf.POS2TILE(player.position.y) - Wolf.POS2TILE(self.y); + + // + // arange 5 direction choices in order of preference + // the four cardinal directions plus the diagonal straight towards + // the player + // + + if (deltax > 0) { + dirtry[1] = Wolf.Math.dir8_east; + dirtry[3] = Wolf.Math.dir8_west; + } else { + dirtry[1] = Wolf.Math.dir8_west; + dirtry[3] = Wolf.Math.dir8_east; + } + + if( deltay > 0 ) { + dirtry[2] = Wolf.Math.dir8_north; + dirtry[4] = Wolf.Math.dir8_south; + } else { + dirtry[2] = Wolf.Math.dir8_south; + dirtry[4] = Wolf.Math.dir8_north; + } + + // randomize a bit for dodging + if (Math.abs(deltax) > Math.abs(deltay)) { + tdir = dirtry[1]; dirtry[1]=dirtry[2]; dirtry[2]=tdir; // => swap dirtry[1] & dirtry[2] + tdir = dirtry[3]; dirtry[3]=dirtry[4]; dirtry[4]=tdir; // => swap dirtry[3] & dirtry[4] + } + + if (Wolf.Random.rnd() < 128) { + tdir = dirtry[1]; dirtry[1]=dirtry[2]; dirtry[2]=tdir; + tdir = dirtry[3]; dirtry[3]=dirtry[4]; dirtry[4]=tdir; + } + + dirtry[0] = Wolf.Math.diagonal[dirtry[1]][dirtry[2]]; + + // try the directions util one works + for (i=0; i < 5; ++i) { + if (dirtry[i] == Wolf.Math.dir8_nodir || dirtry[i] == turnaround) { + continue; + } + if (changeDir(self, dirtry[i], level)) { + return; + } + } + + // turn around only as a last resort + if (turnaround != Wolf.Math.dir8_nodir) { + if (changeDir(self, turnaround, level)) { + return; + } + } + + + + self.dir = Wolf.Math.dir8_nodir; + } + + + /** + * @memberOf Wolf.AI + */ + function T_Stand(self, game, tics) { + findTarget(self, game, tics); + } + + /** + * @memberOf Wolf.AI + */ + function T_Path(self, game, tics) { + var level = game.level; + if (findTarget(self, game, tics)) { + return; + } + + if (!self.speed) { + return; // if patroling with a speed of 0 + } + + if (self.dir == Wolf.Math.dir8_nodir) { + path(self, game); + + if (self.dir == Wolf.Math.dir8_nodir) { + return; // all movement is blocked + } + } + T_Advance(self, game, path, tics); + } + + + /** + * @description Try to damage the player. + * @memberOf Wolf.AI + */ + function T_Shoot(self, game, tics) { + var level = game.level, + player = game.player, + dx, dy, dist, + hitchance, + damage; + + if (!level.state.areabyplayer[self.areanumber]) { + return; + } + + if (!Wolf.Level.checkLine(self.x, self.y, player.position.x, player.position.y, level)) { + return; // player is behind a wall + } + + dx = Math.abs(Wolf.POS2TILE(self.x ) - Wolf.POS2TILE(player.position.x)); + dy = Math.abs(Wolf.POS2TILE(self.y ) - Wolf.POS2TILE(player.position.y)); + dist = Math.max(dx, dy); + + if (self.type == Wolf.en_ss || self.type == Wolf.en_boss ) + { + dist = dist * 2 / 3; // ss are better shots + } + + if (player.speed >= Wolf.RUNSPEED) { + hitchance = 160; + } else { + hitchance = 256; + } + + // if guard is visible by player + // player can see to dodge + // (if CheckLine both player & enemy see each other) + // So left only check if guard is in player's fov: FIXME: not fixed fov! + var trans = Wolf.Math.transformPoint(self.x, self.y, player.position.x, player.position.y); + if (Wolf.Angle.diff(trans, Wolf.FINE2DEG(player.angle)) < (Math.PI/3)) { + hitchance -= dist * 16; + } else { + hitchance -= dist * 8; + } + + // see if the shot was a hit + if (Wolf.Random.rnd() < hitchance) { + if (dist < 2) { + damage = Wolf.Random.rnd() >> 2; + } else if (dist < 4) { + damage = Wolf.Random.rnd() >> 3; + } else { + damage = Wolf.Random.rnd() >> 4; + } + Wolf.Player.damage(player, self, damage); + } + + switch (self.type) { + case Wolf.en_ss: + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "sfx/024.wav", 1, Wolf.ATTN_NORM, 0); + break; + case Wolf.en_gift: + case Wolf.en_fat: + case Wolf.en_mecha: + case Wolf.en_hitler: + case Wolf.en_boss: + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "sfx/022.wav", 1, Wolf.ATTN_NORM, 0); + break; + default: + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "sfx/049.wav", 1, Wolf.ATTN_NORM, 0); + break; + } + } + + + /** + * @description + * @memberOf Wolf.AI + */ + function T_Chase(self, game, tics) { + var level = game.level, + player = game.player, + dx, dy, + dist, + chance, + shouldDodge = false; + + // if (gamestate.victoryflag) return; + if (Wolf.Level.checkLine(self.x, self.y, player.position.x, player.position.y, level)) { // got a shot at player? + dx = Math.abs(Wolf.POS2TILE(self.x) - Wolf.POS2TILE(player.position.x)); + dy = Math.abs(Wolf.POS2TILE(self.y) - Wolf.POS2TILE(player.position.y)); + dist = Math.max(dx, dy); + if (!dist || (dist == 1 && self.distance < 16)) { + chance = 300; + } else { + chance = (tics << 4) / dist; // 100/dist; + } + + if (Wolf.Random.rnd() < chance) { + // go into attack frame + Wolf.Actors.stateChange(self, Wolf.st_shoot1); + return; + } + shouldDodge = true; + } + + + if (self.dir == Wolf.Math.dir8_nodir) { + if (shouldDodge) { + dodge(self, game); + } else { + chase(self, game); + } + + if (self.dir == Wolf.Math.dir8_nodir) { + return; // object is blocked in + } + self.angle = Wolf.Math.dir8angle[self.dir]; + } + + T_Advance(self, game, shouldDodge ? dodge : chase, tics); + + } + + + /** + * @description + * @memberOf Wolf.AI + */ + function T_DogChase(self, game, tics) { + var level = game.level, + player = game.player, + dx, dy; + + if (self.dir == Wolf.Math.dir8_nodir) { + dodge(self, game); + self.angle = Wolf.Math.dir8angle[ self.dir ]; + if (self.dir == Wolf.Math.dir8_nodir) { + return; // object is blocked in + } + } + + // + // check for bite range + // + dx = Math.abs(player.position.x - self.x) - Wolf.TILEGLOBAL / 2; + if (dx <= Wolf.MINACTORDIST) { + dy = Math.abs(player.position.y - self.y) - Wolf.TILEGLOBAL / 2; + if (dy <= Wolf.MINACTORDIST) { + Wolf.Actors.stateChange(self, Wolf.st_shoot1); + return; // bite player! + } + } + + T_Advance(self, game, dodge, tics); + } + + + /** + * @description Try to damage the player. + * @memberOf Wolf.AI + */ + function T_BossChase(self, game, tics) { + var level = game.level, + player = game.player, + dx, dy, dist, + think, + shouldDodge = false; + + dx = Math.abs(self.tile.x - Wolf.POS2TILE(player.position.x)); + dy = Math.abs(self.tile.y - Wolf.POS2TILE(player.position.y)); + dist = Math.max(dx, dy); + + if (Wolf.Level.checkLine(self.x, self.y, player.position.x, player.position.y, level)) { + // got a shot at player? + if (Wolf.Random.rnd() < tics << 3) { + // go into attack frame + Wolf.Actors.stateChange(self, Wolf.st_shoot1); + return; + } + shouldDodge = true; + } + + if( self.dir == Wolf.Math.dir8_nodir ) { + if (shouldDodge) { + dodge(self, game); + } else { + chase(self, game); + } + + if( self.dir == Wolf.Math.dir8_nodir ) { + // object is blocked in + return; + } + } + + think = dist < 4 ? retreat : (shouldDodge ? dodge : chase); + T_Advance(self, game, think, tics); + } + + + /** + * @description + * @memberOf Wolf.AI + */ + function T_Fake(self, game, tics) { + var level = game.level, + player = game.player; + + if (Wolf.Level.checkLine(self.x, self.y, player.position.x, player.position.y, level)) { + if (Wolf.Random.rnd() < tics << 1) { + // go into attack frame + Wolf.Actors.stateChange(self, Wolf.st_shoot1); + return; + } + } + + if (self.dir == Wolf.Math.dir8_nodir) { + dodge(self, game); + if (self.dir == Wolf.Math.dir8_nodir ) { + // object is blocked in + return; + } + } + + T_Advance(self, game, dodge, tics); + } + + + /** + * @description + * @private + */ + function T_Advance(self, game, think, tics) { + var level = game.level, + move, door; + + if (!think) { + Wolf.log("Warning: Advance without proc\n"); + return; + } + + move = self.speed * tics; + while (move > 0) { + // waiting for a door to open + if (self.waitfordoorx) { + door = level.state.doorMap[self.waitfordoorx][self.waitfordoory]; + + Wolf.Doors.open(door); + if (door.action != Wolf.dr_open) { + return; // not opened yet... + } + self.waitfordoorx = self.waitfordoory = 0; // go ahead, the door is now open + } + + if (move < self.distance ) { + T_Move(self, game, move); + break; + } + + // fix position to account for round off during moving + self.x = Wolf.TILE2POS(self.tile.x); + self.y = Wolf.TILE2POS(self.tile.y); + + move -= self.distance; + + // think: Where to go now? + think(self, game, tics); + + self.angle = Wolf.Math.dir8angle[self.dir]; + if (self.dir == Wolf.Math.dir8_nodir) { + return; // all movement is blocked + } + } + } + + /** + * @description Moves object for distance in global units, in self.dir direction. + * @memberOf Wolf.AI + */ + function T_Move(self, game, dist) { + var level = game.level, + player = game.player; + + if (self.dir == Wolf.Math.dir8_nodir || !dist) { + return; + } + self.x += dist * Wolf.Math.dx8dir[self.dir]; + self.y += dist * Wolf.Math.dy8dir[self.dir]; + + // check to make sure it's not on top of player + if (Math.abs(self.x - player.position.x) <= Wolf.MINACTORDIST) { + if (Math.abs(self.y - player.position.y) <= Wolf.MINACTORDIST) { + var t = self.type; + if (t == Wolf.en_blinky || t == Wolf.en_clyde || t == Wolf.en_pinky || t == Wolf.en_inky || t == Wolf.en_spectre) { + Wolf.Player.damage(player, self, 2); // ghosts hurt player! + } + // + // back up + // + self.x -= dist * Wolf.Math.dx8dir[self.dir]; + self.y -= dist * Wolf.Math.dy8dir[self.dir]; + return; + } + } + + self.distance -= dist; + if (self.distance < 0) { + self.distance = 0; + } + } + + /** + * @description + * @memberOf Wolf.AI + */ + function T_Ghosts(self, game, tics) { + var level = game.level, + player = game.player; + + if (self.dir == Wolf.Math.dir8_nodir) { + chase(self, game); + if (self.dir == Wolf.Math.dir8_nodir ) { + return; // object is blocked in + } + self.angle = Wolf.Math.dir8angle[self.dir]; + } + T_Advance(self, game, chase, tics); + } + + /** + * @description + * @memberOf Wolf.AI + */ + function T_Bite(self, game, tics) { + var level = game.level, + player = game.player, + dx, dy; + + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_VOICE, "sfx/002.wav", 1, Wolf.ATTN_NORM, 0); + + dx = Math.abs(player.position.x - self.x) - Wolf.TILEGLOBAL; + if (dx <= Wolf.MINACTORDIST) { + dy = Math.abs(player.position.y - self.y) - Wolf.TILEGLOBAL; + if (dy <= Wolf.MINACTORDIST) { + if (Wolf.Random.rnd() < 180) { + Wolf.Player.damage(player, self, Wolf.Random.rnd() >> 4); + return; + } + } + } + } + + + /** + * @description + * @memberOf Wolf.AI + */ + function T_UShoot(self, game, tics) { + var level = game.level, + player = game.player, + dx, dy, + dist; + + T_Shoot(self, game, tics); + + dx = Math.abs(self.tile.x - Wolf.POS2TILE(player.position.x)); + dy = Math.abs(self.tile.y - Wolf.POS2TILE(player.position.y)); + dist = Math.max(dx, dy); + + if (dist <= 1) { + Wolf.Player.damage(player, self, 10); + } + } + + + /** + * @description + * @memberOf Wolf.AI + */ + function T_Launch(self, game, tics) { + var level = game.level, + player = game.player, + proj, iangle; + + iangle = Wolf.Math.transformPoint(self.x, self.y, player.position.x, player.position.y) + Math.PI; + if (iangle > 2 * Math.PI) { + iangle -= 2 * Math.PI; + } + + if (self.type == Wolf.en_death) { + // death knight launches 2 rockets with 4 degree shift each. + T_Shoot(self, game, tics); + if (self.state == Wolf.st_shoot2) { + iangle = Wolf.Math.normalizeAngle(iangle - Wolf.DEG2RAD(4)); + } else { + iangle = Wolf.Math.normalizeAngle(iangle + Wolf.DEG2RAD(4)); + } + } + + proj = Wolf.Actors.getNewActor(level); + if (proj == null) { + return; + } + + proj.x = self.x; + proj.y = self.y; + + proj.tile.x = self.tile.x; + proj.tile.y = self.tile.y; + + proj.state = Wolf.st_stand; + proj.ticcount = 1; + proj.dir = Wolf.Math.dir8_nodir; + + proj.angle = Wolf.RAD2FINE(iangle)>>0; + + proj.speed = 0x2000; + proj.flags = Wolf.FL_NONMARK; // FL_NEVERMARK; + proj.sprite = Wolf.Sprites.getNewSprite(level); + + switch(self.type) { + case Wolf.en_death: + proj.type = Wolf.en_hrocket; + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "lsfx/078.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_angel: + proj.type = Wolf.en_spark; + proj.state = Wolf.st_path1; + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "lsfx/069.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_fake: + proj.type = Wolf.en_fire; + proj.state = Wolf.st_path1; + proj.flags = Wolf.FL_NEVERMARK; + proj.speed = 0x1200; + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "lsfx/069.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.en_schabbs: + proj.type = Wolf.en_needle; + proj.state = Wolf.st_path1; + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "lsfx/008.wav", 1, Wolf.ATTN_NORM, 0); + break; + + default: + proj.type = Wolf.en_rocket; + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "lsfx/085.wav", 1, Wolf.ATTN_NORM, 0); + } + + } + + + + /** + * @description Called when projectile is airborne. + * @private + * @param {object} self The projectile actor object. + * @param {object} level The level object. + * @returns {boolean} True if move ok, otherwise false. + */ + function projectileTryMove(self, level) { + var PROJSIZE = 0x2000, + xl, yl, xh, yh, x, y; + + xl = (self.x - PROJSIZE) >> Wolf.TILESHIFT; + yl = (self.y - PROJSIZE) >> Wolf.TILESHIFT; + + xh = (self.x + PROJSIZE) >> Wolf.TILESHIFT; + yh = (self.y + PROJSIZE) >> Wolf.TILESHIFT; + + // Checking for solid walls: + for (y = yl; y <= yh; ++y) { + for (x = xl; x <= xh; ++x) { + // FIXME: decide what to do with statics & Doors! + if (level.tileMap[x][y] & (Wolf.WALL_TILE | Wolf.BLOCK_TILE)) { + return false; + } + if (level.tileMap[x][y] & Wolf.DOOR_TILE) { + if (Wolf.Doors.opened(level.state.doorMap[x][y]) != Wolf.DOOR_FULLOPEN) { + return false; + } + } + } + } + // FIXME: Projectile will fly through objects (even guards & columns) - must fix to create rocket launcher! + return true; + } + + + /** + * @description Called when projectile is airborne. + * @memberOf Wolf.AI + * @param {object} self The enemy actor object. + * @param {object} level The level object. + * @param {object} player The player object. + * @param {number} tics The number of tics. + * @returns {boolean} True if move ok, otherwise false. + */ + function T_Projectile(self, game, tics) { + var level = game.level, + player = game.player, + PROJECTILESIZE = 0xC000, + deltax, deltay, + speed, damage; + + speed = self.speed * tics; + + deltax = (speed * Wolf.Math.CosTable[self.angle])>>0; + deltay = (speed * Wolf.Math.SinTable[self.angle])>>0; + + if (deltax > Wolf.TILEGLOBAL) { + deltax = Wolf.TILEGLOBAL; + } + if (deltax < -Wolf.TILEGLOBAL) { + deltax = -Wolf.TILEGLOBAL; // my + } + if (deltay > Wolf.TILEGLOBAL) { + deltay = Wolf.TILEGLOBAL; + } + if (deltay < -Wolf.TILEGLOBAL) { + deltay = -Wolf.TILEGLOBAL; // my + } + + self.x += deltax; + self.y += deltay; + + deltax = Math.abs(self.x - player.position.x); + deltay = Math.abs(self.y - player.position.y); + + if (!projectileTryMove(self, level)) { + if (self.type == Wolf.en_rocket || self.type == Wolf.en_hrocket ) { + // rocket ran into obstacle, draw explosion! + Wolf.Sound.startSound(player.position, self, 1, Wolf.CHAN_WEAPON, "lsfx/086.wav", 1, Wolf.ATTN_NORM, 0); + Wolf.Actors.stateChange(self, Wolf.st_die1); + } else { + Wolf.Actors.stateChange(self, Wolf.st_remove); // mark for removal + } + return; + } + + if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE) { + // hit the player + switch (self.type) { + case Wolf.en_needle: + damage = (Wolf.Random.rnd() >> 3) + 20; + break; + + case Wolf.en_rocket: + case Wolf.en_hrocket: + case Wolf.en_spark: + damage = (Wolf.Random.rnd()>>3) + 30; + break; + + case Wolf.en_fire: + damage = (Wolf.Random.rnd() >> 3); + break; + + default: + damage = 0; + break; + } + + Wolf.Player.damage(player, self, damage); + Wolf.Actors.stateChange(self, Wolf.st_remove); // mark for removal + return; + } + + self.tile.x = self.x >> Wolf.TILESHIFT; + self.tile.y = self.y >> Wolf.TILESHIFT; + } + + /** + * @description + * @memberOf Wolf.AI + */ + function T_BJRun(self, game, tics) { + var move = Wolf.BJRUNSPEED * tics; + + T_Move(self, game, move); + + if (!self.distance) { + self.distance = Wolf.TILEGLOBAL; + if (!(--self.temp2)) { + Wolf.Actors.stateChange(self, Wolf.st_shoot1); + self.speed = Wolf.BJJUMPSPEED; + return; + } + } + } + + /** + * @description + * @memberOf Wolf.AI + */ + function T_BJJump(self, game, tics) { + //var move = Wolf.BJRUNSPEED * tics; + //T_Move(self, game, move); + } + + /** + * @description + * @memberOf Wolf.AI + */ + function T_BJYell(self, game, tics) { + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_VOICE, "sfx/082.wav", 1, Wolf.ATTN_NORM, 0); + } + + /** + * @description + * @memberOf Wolf.AI + */ + function T_BJDone(self, game, tics) { + Wolf.Player.playstate = Wolf.ex_victory; // exit castle tile + //Wolf.Player.playstate = Wolf.ex_complete; + Wolf.Game.endEpisode(game); + } + + + return { + T_Stand : T_Stand, + T_Path : T_Path, + T_Ghosts : T_Ghosts, + T_Bite : T_Bite, + T_Shoot : T_Shoot, + T_UShoot : T_UShoot, + T_Launch : T_Launch, + T_Chase : T_Chase, + T_DogChase : T_DogChase, + T_BossChase : T_BossChase, + T_Fake : T_Fake, + T_Projectile : T_Projectile, + T_BJRun : T_BJRun, + T_BJJump : T_BJJump, + T_BJYell : T_BJYell, + T_BJDone : T_BJDone + }; + +})(); \ No newline at end of file diff --git a/js/angle.js b/js/angle.js new file mode 100644 index 0000000..293f61c --- /dev/null +++ b/js/angle.js @@ -0,0 +1,143 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Angle math + */ +Wolf.Angle = (function() { + + Wolf.setConsts({ + DEG2RAD : function(a) { return a * 0.01745329251994329576; }, // a * M_PI / 180.0f + RAD2DEG : function(a) { return a / 0.01745329251994329576; }, // a * 180.0f / M_PI + ANGLE2SHORT : function(x) { return ((x * 65536 / 360)>>0) & 65535; }, + SHORT2ANGLE : function(x) { return x * 360.0 / 65536; } + }); + + /** + * @description Finds the difference between two angles. + * @memberOf Wolf.Angle + * @param {number} angle1 Angle in radians. + * @param {number} angle2 Angle in radians. + * @returns {number} The absolute difference between two angles, this will always be between 0 and 180 degrees. + */ + function diff(angle1, angle2) { + var d; + + if (angle1 > angle2) { + d = angle1 - angle2; + } else { + d = angle2 - angle1; + } + + if (d > Math.PI) { + return 2 * Math.PI - d; + } else { + return d; + } + } + + /** + * @description Clockwise distance between two angles. + * @memberOf Wolf.Angle + * @param {number} angle1 Angle in radians. + * @param {number} angle2 Angle in radians. + * @returns {number} The clockwise distance from angle2 to angle1, this may be greater than 180 degrees. + */ + function distCW(angle1, angle2) { + if (angle1 > angle2) { + return angle1 - angle2; + } else { + return angle1 + 2 * Math.PI - angle2; + } + } + + /** + * @description Linear interpolate between angle from and to by fraction frac. + * @memberOf Wolf.Angle + * @param {number} from Angle in radians. + * @param {number} to Angle in radians. + * @param {number} frac Fraction. + * @returns {number} + */ + function interpolate(from, to, frac) { + var d = diff(from, to) * frac; + + if (distCW(to, from) >= Math.PI) { + return from - diff; + } else { + return from + diff; + } + } + + + /** + * @description Normalize angle. + * @memberOf Wolf.Angle + * @param {number} angle + * @returns {number} + */ + function normalize(angle) { + while (angle < 0) { + angle += (2 * Math.PI); + } + while (angle >= (2 * Math.PI)) { + angle -= (2 * Math.PI); + } + return angle; + } + + + + /** + * @description Linear interpolate allowing for the Modulo 360 problem. + * @memberOf Wolf.Angle + * @param {number} from Angle in radians. + * @param {number} to Angle in radians. + * @param {number} frac fraction. + * @returns {number} + */ + + function lerp(from, to, frac) { + if (to - from > 180) { + to -= 360; + } + if (to - from < -180) { + to += 360; + } + return from + frac * (to - from); + } + + return { + diff : diff, + distCW : distCW, + normalize : normalize, + interpolate : interpolate, + lerp : lerp + } + +})(); \ No newline at end of file diff --git a/js/areas.js b/js/areas.js new file mode 100644 index 0000000..5cf0a4b --- /dev/null +++ b/js/areas.js @@ -0,0 +1,149 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Area management + */ +Wolf.Areas = (function() { + /* + Notes: + + Open doors connect two areas, so sounds will travel between them and sight + will be checked when the player is in a connected area. + + Areaconnect is incremented/decremented by each door. If >0 they connect. + + Every time a door opens or closes the areabyplayer matrix gets recalculated. + An area is true if it connects with the player's current spor. + + */ + + /** + * @description Initialize areas + * @memberOf Wolf.Areas + * @param {object} levelState The level state object + * @param {number} areanumber Initial area + */ + function init(level, areanumber) { + level.state.areaconnect = []; + level.state.areabyplayer = []; + for (var i=0;i= Wolf.NUMAREAS) { + throw new Error("areanumber >= Wolf.NUMAREAS"); + } + + level.state.areabyplayer = []; + level.state.areabyplayer[areanumber] = true; + + recursiveConnect(level, areanumber); + for (i = 0; i < Wolf.NUMAREAS; i++) { + if (level.state.areabyplayer[i]) { + c++; + } + } + } + + /** + * @description Join ares + * @memberOf Wolf.Areas + * @param {object} level The level object + * @param {number} area1 Area 1 + * @param {number} area2 Area 2 + */ + function join(level, area1, area2) { + if (area1 < 0 || area1 >= Wolf.NUMAREAS) { + throw new Error("area1 < 0 || area1 >= Wolf.NUMAREAS"); + } + if (area2 < 0 || area2 >= Wolf.NUMAREAS) { + throw new Error("area2 < 0 || area2 >= Wolf.NUMAREAS"); + } + level.state.areaconnect[area1][area2]++; + level.state.areaconnect[area2][area1]++; + } + + /** + * @description Disconnect ares + * @memberOf Wolf.Areas + * @param {object} level The level object + * @param {number} area1 Area 1 + * @param {number} area2 Area 2 + */ + function disconnect(level, area1, area2) { + if (area1 < 0 || area1 >= Wolf.NUMAREAS) { + throw new Error("area1 < 0 || area1 >= Wolf.NUMAREAS"); + } + if (area2 < 0 || area2 >= Wolf.NUMAREAS) { + throw new Error("area2 < 0 || area2 >= Wolf.NUMAREAS"); + } + level.state.areaconnect[area1][area2]--; + level.state.areaconnect[area2][area1]--; + } + + return { + init : init, + connect : connect, + join : join, + disconnect : disconnect + }; + +})(); + diff --git a/js/doors.js b/js/doors.js new file mode 100644 index 0000000..7a16264 --- /dev/null +++ b/js/doors.js @@ -0,0 +1,422 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Door management + */ +Wolf.Doors = (function() { + + Wolf.setConsts({ + CLOSEWALL : Wolf.MINDIST, // Space between wall & player + MAXDOORS : 64, // max number of sliding doors + + MAX_DOORS : 256, // jseidelin: doesn't look like this is used? + DOOR_TIMEOUT : 300, + DOOR_MINOPEN : 50, + DOOR_FULLOPEN : 63, + DOOR_VERT : 255, + DOOR_HORIZ : 254, + DOOR_E_VERT : 253, + DOOR_E_HORIZ : 252, + DOOR_G_VERT : 251, + DOOR_G_HORIZ : 250, + DOOR_S_VERT : 249, + DOOR_S_HORIZ : 248, + FIRST_DOOR : 248, + LAST_LOCK : 251, + + TEX_DOOR : 98, + // TEX_DOOR : 126, + + dr_closing : -1, + dr_closed : 0, + dr_opening : 1, + dr_open : 2 + }); + Wolf.setConsts({ + // texture IDs used by cache routines + TEX_DDOOR : (0 + Wolf.TEX_DOOR), // Simple Door + TEX_PLATE : (2 + Wolf.TEX_DOOR), // Door Plate + TEX_DELEV : (4 + Wolf.TEX_DOOR), // Elevator Door + TEX_DLOCK : (6 + Wolf.TEX_DOOR) // Locked Door + }); + + + /** + * @description Reset doors in the level + * @memberOf Wolf.Doors + * @param {object} level The level object. + */ + function reset(level) { + level.state.numDoors = 0; + + for (var x=0;x<64;x++) { + level.state.doorMap[x] = []; + for (var y=0;y<64;y++) { + level.state.doorMap[x][y] = 0; + } + } + } + + /** + * @description Spawn a door at the specified position. + * @memberOf Wolf.Doors + * @param {object} level The level object. + * @param {number} x The x coordinate. + * @param {number} y The y coordinate. + * @param {number} type The door type. + * @returns {number} The index of the new door. + */ + function spawn(level, x, y, type) { + if (level.state.numDoors >= Wolf.MAXDOORS) { + throw new Error("Too many Doors on level!"); + } + var door = level.state.doorMap[x][y] = { + type : -1, + vertical : 0, + texture : -1, + ticcount : 0 + }; + + switch(type) { + case 0x5A: + door.type = Wolf.DOOR_VERT; + door.vertical = true; + door.texture = Wolf.TEX_DDOOR + 1; + break; + case 0x5B: + door.type = Wolf.DOOR_HORIZ; + door.vertical = false; + door.texture = Wolf.TEX_DDOOR; + break; + case 0x5C: + door.type = Wolf.DOOR_G_VERT; + door.vertical = true; + door.texture = Wolf.TEX_DLOCK; + break; + case 0x5D: + door.type = Wolf.DOOR_G_HORIZ; + door.vertical = false; + door.texture = Wolf.TEX_DLOCK; + break; + case 0x5E: + door.type = Wolf.DOOR_S_VERT; + door.vertical = true; + door.texture = Wolf.TEX_DLOCK + 1; + break; + case 0x5F: + door.type = Wolf.DOOR_S_HORIZ; + door.vertical = false; + door.texture = Wolf.TEX_DLOCK + 1; + break; + case 0x64: + door.type = Wolf.DOOR_E_VERT; + door.vertical = true; + door.texture = Wolf.TEX_DELEV + 1; + break; + case 0x65: + door.type = Wolf.DOOR_E_HORIZ; + door.vertical = false; + door.texture = Wolf.TEX_DELEV; + break; + default: + throw new Error("Unknown door type: " + type); + } + + door.tile = { + x : x, + y : y + }; + door.action = Wolf.dr_closed; + + level.state.doors[level.state.numDoors] = door; + level.state.numDoors++; + + return level.state.numDoors - 1; + } + + /** + * @description Check to see if a door is open. If there are no doors in tile assume a closed door! + * @memberOf Wolf.Doors + * @param {object} doors The door object. + * @returns {number} DOOR_FULLOPEN if door is opened, + 0 if door is closed, + >0 = Wolf.DOOR_FULLOPEN) { // door fully opened! + door.action = Wolf.dr_open; + door.ticcount = 0; + } else { // opening! + if (door.ticcount == 0) { + // door is just starting to open, so connect the areas + Wolf.Areas.join(level, door.area1, door.area2); + Wolf.Areas.connect(level, player.areanumber); + + if (level.state.areabyplayer[door.area1]) { // Door Opening sound! + Wolf.Sound.startSound(player.position, doorPos, 1, Wolf.CHAN_AUTO, "sfx/010.wav", 1, Wolf.ATTN_STATIC, 0); + } + } + + door.ticcount += tics; + + if (door.ticcount > Wolf.DOOR_FULLOPEN) { + door.ticcount = Wolf.DOOR_FULLOPEN; + } + } + break; + + case Wolf.dr_closing: + if (door.ticcount <= 0) { // door fully closed! disconnect areas! + Wolf.Areas.disconnect(level, door.area1, door.area2); + Wolf.Areas.connect(level, player.areanumber); + door.ticcount = 0; + door.action = Wolf.dr_closed; + } else { // closing! + if (door.ticcount == Wolf.DOOR_FULLOPEN) { + if (level.state.areabyplayer[door.area1]) { // Door Closing sound! + Wolf.Sound.startSound(player.position, doorPos, 1, Wolf.CHAN_AUTO, "sfx/007.wav", 1, Wolf.ATTN_STATIC, 0); + } + } + door.ticcount -= tics; + if (door.ticcount < 0) { + door.ticcount = 0; + } + } + break; + + case Wolf.dr_open: + if (door.ticcount > Wolf.DOOR_MINOPEN) { + // If player or something is in door do not close it! + if (!canCloseDoor(level, player, door.tile.x, door.tile.y, door.vertical)) { + door.ticcount = Wolf.DOOR_MINOPEN; // do not close door immediately! + } + } + if (door.ticcount >= Wolf.DOOR_TIMEOUT) { + // Door timeout, time to close it! + door.action = Wolf.dr_closing; + door.ticcount = Wolf.DOOR_FULLOPEN; + } else { + // Increase timeout! + door.ticcount += tics; + } + break; + } // End switch lvldoors->Doors[ n ].action + } // End for n = 0 ; n < lvldoors->numDoors ; ++n + } + + /** + * @description Set the areas doors in a level + * @memberOf Wolf.Doors + * @param {object} level The level object. + * @param {array} areas The areas map. + */ + function setAreas(level) { + var n, x, y, + door; + for (n=0; n= 0 ? level.areas[x + 1][y] : 0; + door.area2 = level.areas[x - 1][y] >= 0 ? level.areas[x - 1][y] : 0; + } else { + door.area1 = level.areas[x][y + 1] >= 0 ? level.areas[x][y + 1] : 0; + door.area2 = level.areas[x][y - 1] >= 0 ? level.areas[x][y - 1] : 0; + } + } + } + + + /** + * @description Open a door + * @memberOf Wolf.Doors + * @param {object} doors The door object. + */ + function open(door) { + if (door.action == Wolf.dr_open) { + door.ticcount = 0; // reset opened time + } else { + door.action = Wolf.dr_opening; // start opening it + } + } + + /** + * @description Change the state of a door + * @private + * @param {object} level The level object. + * @param {object} player The player object. + * @param {object} doors The door object. + */ + function changeDoorState(level, player, door) { + if (door.action < Wolf.dr_opening ) { + open(door); + } else if (door.action == Wolf.dr_open && canCloseDoor(level, player, door.tile.x, door.tile.y, door.vertical)) { + // !@# for the iphone with automatic using, don't allow any door close actions + // Door->action = dr_closing; + // Door->ticcount = DOOR_FULLOPEN; + } + } + + + function canCloseDoor(level, player, x, y, vert ) { + var n, + tileX = Wolf.POS2TILE(player.position.x), + tileY = Wolf.POS2TILE(player.position.y), + guard; + + if (tileX == x && tileY == y ) { + return false; + } + + if (vert) { + if (tileY == y) { + if (Wolf.POS2TILE(player.position.x + Wolf.CLOSEWALL) == x) { + return false; + } + if (Wolf.POS2TILE(player.position.x - Wolf.CLOSEWALL) == x) { + return false; + } + } + + for (n = 0; n. +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Episode data + */ +Wolf.Episodes = [ + { + name : "Escape from Wolfenstein", + enabled : true, + levels : [ + { file : "maps/w00.map", partime : 1.5 }, + { file : "maps/w01.map", partime : 2.0 }, + { file : "maps/w02.map", partime : 2.0 }, + { file : "maps/w03.map", partime : 3.5 }, + { file : "maps/w04.map", partime : 3.0 }, + { file : "maps/w05.map", partime : 3.0 }, + { file : "maps/w06.map", partime : 2.5 }, + { file : "maps/w07.map", partime : 2.5 }, + { file : "maps/w08.map", partime : 0.0 }, + { file : "maps/w09.map", partime : 0.0, secret : true } + ] + },{ + name : "Operation: Eisenfaust", + enabled : true, + levels : [ + { file : "maps/w10.map", partime : 1.5 }, + { file : "maps/w11.map", partime : 3.5 }, + { file : "maps/w12.map", partime : 3.0 }, + { file : "maps/w13.map", partime : 2.0 }, + { file : "maps/w14.map", partime : 4.0 }, + { file : "maps/w15.map", partime : 6.0 }, + { file : "maps/w16.map", partime : 1.0 }, + { file : "maps/w17.map", partime : 3.0 }, + { file : "maps/w18.map", partime : 0.0 }, + { file : "maps/w19.map", partime : 0.0, secret : true } + ] + },{ + name : "Die, Fuhrer, Die!", + enabled : true, + levels : [ + { file : "maps/w20.map", partime : 1.5 }, + { file : "maps/w21.map", partime : 1.5 }, + { file : "maps/w22.map", partime : 2.5 }, + { file : "maps/w23.map", partime : 2.5 }, + { file : "maps/w24.map", partime : 3.5 }, + { file : "maps/w25.map", partime : 2.5 }, + { file : "maps/w26.map", partime : 2.0 }, + { file : "maps/w27.map", partime : 6.0 }, + { file : "maps/w28.map", partime : 0.0 }, + { file : "maps/w29.map", partime : 0.0, secret : true } + ] + } +]; + diff --git a/js/file.js b/js/file.js new file mode 100644 index 0000000..3315f38 --- /dev/null +++ b/js/file.js @@ -0,0 +1,217 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Binary file reading + */ +Wolf.File = (function() { + + + /** + * @description Open a file from URL + * @memberOf Wolf.File + * @param {string} url The URL to open + * @param {function} callback Is called when file has been loaded. Second argument is file obj. + */ + function openURL(url, callback) { + var xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 0) { + callback(null, { + data : xhr.responseText, + size : xhr.responseText.length, + position : 0 + }); + } else { + callback(new Error("Server returned HTTP status: " + xhr.status)); + } + } + } + xhr.open("GET", url, true); + xhr.overrideMimeType('text/plain; charset=x-user-defined'); + xhr.send(null); + } + + + function atob(str) { + str = str.replace(/=+$/, ""); + var b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + a, b, c, b1, b2, b3, b4, + chr = String.fromCharCode, + out = []; + for (var i=0,len=str.length;i> 4) & 0x3); + b = ((b2 & 0xF) << 4) | ((b3 >> 2) & 0xF); + c = ((b3 & 0x3) << 6) | (b4 & 0x3F); + + out.push(chr(a), chr(b), chr(c)); + } + return out.join(""); + } + + /** + * @description Open a file from base64 filetable + * @memberOf Wolf.File + * @param {string} filename The name of the file to open + * @param {object} files The filetable + * @param {function} callback Is called when file has been loaded. Second argument is file obj. + */ + function open(filename, files, callback) { + var b64data = files[filename]; + if (b64data) { + var data = atob(b64data); + callback(null, { + data : data, + size : data.length, + position : 0 + }); + } else { + callback(new Error("File not found: " + filename)); + } + } + + /** + * @description Read an unsigned 8-bit integer from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @returns {number} + */ + function readUInt8(f) { + var b = f.data.charCodeAt(f.position) & 0xFF + f.position++; + return b; + } + + /** + * @description Read a signed 8-bit integer from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @returns {number} + */ + function readInt8(f) { + var v = readUInt8(f); + return v > 127 ? v - 256 : v; + } + + /** + * @description Read an unsigned 16-bit integer from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @returns {number} + */ + function readUInt16(f) { + var v = readUInt8(f) + (readUInt8(f) << 8); + return (v < 0) ? v + 0x10000 : v; + } + + /** + * @description Read a signed 16-bit integer from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @returns {number} + */ + function readInt16(f) { + var v = readUInt16(f); + return (v > 0x7fff) ? v - 0x10000 : v; + } + + /** + * @description Read an unsigned 32-bit integer from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @returns {number} + */ + function readUInt32(f) { + var b0 = readUInt8(f), + b1 = readUInt8(f), + b2 = readUInt8(f), + b3 = readUInt8(f), + v = ((((b3 << 8) + b2) << 8) + b1 << 8) + b0; + return (v < 0) ? v + 0x100000000 : v; + } + + /** + * @description Read a signed 32-bit int from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @returns {number} + */ + function readInt32(f) { + var v = readUInt32(f); + return (v > 0x7fffffff) ? v - 0x100000000 : v; + } + + /** + * @description Read a string from a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @param {number} length The length of the string + * @returns {string} + */ + function readString(f, length) { + var str = f.data.substr(f.position, length); + f.position += length; + return str; + } + + /** + * @description Read an array of bytes a file and advance the file position. + * @memberOf Wolf.File + * @param {object} f The file + * @param {number} num The number of bytes to read + * @returns {array} + */ + function readBytes(f, num) { + var b = []; + for (var i=0;i. +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Game management + */ +Wolf.Game = (function() { + Wolf.setConsts({ + BUTTON_ATTACK : 1, + BUTTON_USE : 2, + BUTTON_ANY : 128, // any key whatsoever + + BASEMOVE : 35, + RUNMOVE : 70, + MOVESCALE : 150, + BACKMOVESCALE : 100, + MAXMOUSETURN : 10, + TURNANGLESCALE : 300, + MOUSEDEADBAND : 0.2, + + gd_baby : 0, + gd_easy : 1, + gd_medium : 2, + gd_hard : 3 + }); + + var rendering = false, + playing = false, + fsInit = false, + hndRender = 0, + hndCycle = 0, + hndFps = 0, + lastFPSTime = 0, + lastFrame = 0, + frameNum = 0, + cycleNum = 0, + mouseEnabled = false, + paused = false, + intermissionAnim = 0, + currentGame = null, + levelMusic, + processAI = true, + keyInputActive = false, + preloadTextures = {}, + preloadSprites = {}, + + controls = { + up : ["UP"], + left : ["LEFT"], + down : ["DOWN"], + right : ["RIGHT"], + run : ["SHIFT"], + attack : ["X"], + use : ["SPACE"], + strafe : ["Z"], + weapon1 : ["1"], + weapon2 : ["2"], + weapon3 : ["3"], + weapon4 : ["4"] + }, + ticsPerSecond = 70, + lastTimeCount = 0; + + /** + * @description Build the movement, angles, and buttons for a frame of action: + * Player.angle + * Player.cmd.buttons + * Player.cmd.forwardMove + * Player.cmd.sideMove + * @private + * @param {object} player The player object. + * @param {number} tics The number of tics since last frame. + */ + function updatePlayerControls(player, tics) { + var moveValue, + running = false, + strafing = false, + leftKey = false, + rightKey = false, + downKey = false, + upKey = false, + changeWeapon = -1, + mouseMovement, + mouseCoords; + + player.cmd.buttons = 0; + player.cmd.forwardMove = 0; + player.cmd.sideMove = 0; + + leftKey = Wolf.Input.checkKeys(controls.left); + rightKey = Wolf.Input.checkKeys(controls.right); + downKey = Wolf.Input.checkKeys(controls.down); + upKey = Wolf.Input.checkKeys(controls.up); + + running = Wolf.Input.checkKeys(controls.run); + strafing = Wolf.Input.checkKeys(controls.strafe); + moveValue = (running ? Wolf.RUNMOVE : Wolf.BASEMOVE); + + if (Wolf.Input.checkKeys(controls.attack) || (mouseEnabled && Wolf.Input.leftMouseDown())) { + player.cmd.buttons |= Wolf.BUTTON_ATTACK; + } + + if (mouseEnabled && Wolf.Input.rightMouseDown()) { + if (mouseCoords = Wolf.Input.getMouseCoords()) { + player.cmd.forwardMove += - (mouseCoords.y < 0 ? Wolf.MOVESCALE : Wolf.BACKMOVESCALE) * moveValue * mouseCoords.y; + } + } else if (!(upKey && downKey)) { + if (upKey) { + player.cmd.forwardMove += moveValue * Wolf.MOVESCALE; + } + if (downKey) { + player.cmd.forwardMove += -moveValue * Wolf.BACKMOVESCALE; + } + } + + if (mouseEnabled && Wolf.Input.isPointerLocked()) { + mouseMovement = Wolf.Input.getMouseMovement(); + player.angle -= (mouseMovement.x * Wolf.TURNANGLESCALE * tics)>>0; + } else { + if (leftKey) { + if (strafing) { + player.cmd.sideMove += -moveValue * Wolf.MOVESCALE; + } else { + player.angle += Wolf.TURNANGLESCALE * tics; + } + } + if (rightKey) { + if (strafing) { + player.cmd.sideMove += moveValue * Wolf.MOVESCALE; + } else { + player.angle -= Wolf.TURNANGLESCALE * tics; + } + } + + if (mouseEnabled && (mouseCoords = Wolf.Input.getMouseCoords())) { + if (Math.abs(mouseCoords.x) > Wolf.MOUSEDEADBAND) { + player.angle -= (Wolf.TURNANGLESCALE * tics * (mouseCoords.x + (mouseCoords.x < 0 ? 1 : -1) * Wolf.MOUSEDEADBAND))>>0; + } + } + } + + // change weapon? + if (Wolf.Input.checkKeys(controls.weapon1) && player.items & Wolf.ITEM_WEAPON_1) { + changeWeapon = Wolf.WEAPON_KNIFE; + } else if (Wolf.Input.checkKeys(controls.weapon2) && player.items & Wolf.ITEM_WEAPON_2 && player.ammo[Wolf.AMMO_BULLETS]) { + changeWeapon = Wolf.WEAPON_PISTOL; + } else if (Wolf.Input.checkKeys(controls.weapon3) && player.items & Wolf.ITEM_WEAPON_3 && player.ammo[Wolf.AMMO_BULLETS]) { + changeWeapon = Wolf.WEAPON_AUTO; + } else if (Wolf.Input.checkKeys(controls.weapon4) && player.items & Wolf.ITEM_WEAPON_4 && player.ammo[Wolf.AMMO_BULLETS]) { + changeWeapon = Wolf.WEAPON_CHAIN; + } + if (changeWeapon > -1) { + player.previousWeapon = Wolf.WEAPON_KNIFE; + player.weapon = player.pendingWeapon = changeWeapon; + } + + if (Wolf.Input.checkKeys(controls.use)) { + player.cmd.buttons |= Wolf.BUTTON_USE; + } + } + + /** + * @description Initiate the game cycle to process player and world logic + * @private + * @param {object} game The game object + */ + function startGameCycle(game) { + var deathTics = 0, + deathTicsMax = ticsPerSecond * 2; + + // cancel existing game cycle + if (hndCycle) { + clearTimeout(hndCycle); + hndCycle = 0; + } + + function nextCycle() { + if (!playing) { + return; + } + + hndCycle = setTimeout(nextCycle, 1000 / 30); + cycleNum++; + + if (paused) { + return; + } + + var player = game.player, + level = game.level, + lives, score, + tics = calcTics(); + + if (player.playstate != Wolf.ex_dead) { + updatePlayerControls(player, tics); + + player.angle = Wolf.Math.normalizeAngle(player.angle); + + Wolf.Player.process(game, player, tics); + if (processAI) { + Wolf.Actors.process(game, tics); + } + Wolf.PushWall.process(level, tics); + Wolf.Doors.process(level, player, tics); + } else { + + if (died(game, tics)) { + deathTics += tics; + if (deathTics >= deathTicsMax) { + deathTics = 0; + $("#game .renderer .death").css("display", "none"); + + if (game.player.lives > 0) { + lives = game.player.lives; + score = game.player.startScore; + game.level = Wolf.Level.reload(level); + Wolf.Level.scanInfoPlane(game.level, game.skill); // Spawn items/guards + game.player = Wolf.Player.spawn(game.level.spawn, game.level, game.skill); + game.player.lives = lives - 1; + game.player.score = score; + game.player.startScore = score; + game.level.state.startTime = (new Date).getTime(); + game.level.state.elapsedTime = 0; + } else { + gameOver(game); + return; + } + } else { + $("#game .renderer .death").css({ + display : "block", + backgroundColor : "rgba(255,0,0," + (deathTics / deathTicsMax) + ")" + }); + } + } + } + Wolf.Sprites.clean(level); + updateHUD(game, tics); + + } + + lastTimeCount = (new Date).getTime(); + nextCycle(); + } + + + function died(game, tics) { + var fangle, + dx, dy, + iangle, curangle, + clockwise, + counter, + change, + player = game.player, + killer = player.lastAttacker; + + //gamestate.weapon = -1; // take away weapon + //SD_PlaySound (PLAYERDEATHSND); + + // swing around to face attacker + + dx = killer.x - player.position.x; + dy = player.position.y - killer.y; + + fangle = -Math.atan2(dy,dx); // returns -pi to pi + if (fangle < 0) { + fangle = Math.PI * 2 + fangle; + } + + iangle = Math.round(fangle / (Math.PI * 2) * Wolf.ANGLES); + + curangle = Wolf.FINE2DEG(player.angle); + + if (curangle > iangle) { + counter = curangle - iangle; + clockwise = Wolf.ANGLES - curangle + iangle; + } else { + clockwise = iangle - curangle; + counter = curangle + Wolf.ANGLES - iangle; + } + + if (clockwise < counter) { + // rotate clockwise + if (curangle > iangle) { + curangle -= Wolf.ANGLES; + } + if (curangle == iangle) { + return true; + } else { + change = tics * Wolf.DEATHROTATE; + if (curangle + change > iangle) { + change = iangle - curangle; + } + curangle += change; + if (curangle >= Wolf.ANGLES) { + curangle -= Wolf.ANGLES; + } + player.angle = Wolf.DEG2FINE(curangle); + } + } else { + // rotate counterclockwise + if (curangle < iangle) { + curangle += Wolf.ANGLES; + } + if (curangle == iangle) { + return true; + } else { + change = -tics * Wolf.DEATHROTATE; + if (curangle + change < iangle) { + change = iangle - curangle; + } + curangle += change; + if (curangle < 0) { + curangle += Wolf.ANGLES; + } + player.angle = Wolf.DEG2FINE(curangle); + } + } + return false; + } + + /** + * @description Game over. No more lives. + * @private + * @param {object} game The game object + */ + function gameOver(game) { + playing = false; + rendering = false; + + $("#game .renderer").hide(); + $("#game .fps").hide(); + $("#game .gameover").show(); + endGame(); + + function exit() { + $(document).off("keydown", progress); + $("#game").fadeOut(null, function() { + $("#game .gameover").hide(); + Wolf.Menu.show(); + }); + } + function progress(e) { + if (!$("#game .gameover").is(":visible")) { + exit(); + return; + } + if (e.keyCode == 13 || e.keyCode == 32) { + exit(); + } + } + $(document).on("keydown", progress); + } + + + function victory(game) { + if (game.player.playstate == Wolf.ex_victory) { + return; + } + keyInputActive = false; + Wolf.log("Victory!"); + $("#game .renderer .player-weapon").hide(); + Wolf.Actors.spawnBJVictory(game.player, game.level, game.skill); + game.player.playstate = Wolf.ex_victory; + } + + function endEpisode(game) { + Wolf.Game.startIntermission(game); + } + + /** + * @description Calculate the number of tics since last time calcTics() was called. + * Accumulates fractions. + * @private + * @returns {number} The number of tics + */ + function calcTics() { + var now = (new Date).getTime(), + delta = (now - lastTimeCount) / 1000, + tics = Math.floor(ticsPerSecond * delta); + + lastTimeCount += (tics * 1000 / ticsPerSecond) >> 0; + + return tics; + } + + /** + * @description Update HUD stats + * @private + * @param {string} name The name/class of the player stat (health, ammo, etc.) + * @param {number} value The new value + */ + function updateStat(name, value) { + var numdivs = $("#game .hud ." + name + " .number"); + for (var i=numdivs.length-1;i>=0;i--) { + if (value == 0 && i < numdivs.length-1) { + numdivs[i].style.backgroundPosition = 16 + "px 0"; + } else { + numdivs[i].style.backgroundPosition = - (16 * (value % 10)) + "px 0"; + value = (value / 10) >> 0; + } + } + } + + + + + /** + * @description Update the HUD + * @private + * @param {object} game The game object + */ + function updateHUD(game, tics) { + var player = game.player, + frame = player.weapon * 4 + player.weaponFrame; + + if (player.playstate == Wolf.ex_dead || player.playstate == Wolf.ex_victory) { + $("#game .renderer .player-weapon").css("display", "none"); + } else { + $("#game .renderer .player-weapon").css({ + display : "block", + backgroundPosition : - (frame * Wolf.HUD_WEAPON_WIDTH) + "px 0" + }); + } + + $("#game .hud .weapon").css({ + backgroundPosition : - (player.weapon * 96) + "px 0" + }); + + $("#game .hud .key1").css({ + display : (player.items & Wolf.ITEM_KEY_1) ? "block" : "none" + }); + $("#game .hud .key2").css({ + display : (player.items & Wolf.ITEM_KEY_2) ? "block" : "none" + }); + + updateStat("ammo", player.ammo[Wolf.AMMO_BULLETS]); + updateStat("health", player.health); + updateStat("lives", player.lives); + updateStat("score", player.score); + updateStat("floor", game.levelNum+1); + + drawFace(player, tics); + } + + /** + * @description Update the game display + * @private + * @param {object} game The game object + */ + function updateScreen(game) { + var player = game.player, + level = game.level, + viewport = { + x : player.position.x, + y : player.position.y, + angle : player.angle + }; + + var res = Wolf.Raycaster.traceRays(viewport, level); + + Wolf.Renderer.clear(); + Wolf.Renderer.draw(viewport, level, res.tracers, res.visibleTiles); + } + + + + /** + * @description Update BJ face pic + * @private + * @param {object} player + * @param {number} tics + */ + function drawFace(player, tics) { + var pic; + // decide on the face + player.faceCount += tics; + if (player.faceGotGun && player.faceCount > 0) { + // gotgun will set facecount to a negative number initially, go back + // to normal face with random look after expired. + player.faceGotGun = false; + } + if (player.faceCount > Wolf.Random.rnd()) { + player.faceGotGun = player.faceOuch = false; + player.faceFrame = Wolf.Random.rnd() >> 6; + if( player.faceFrame == 3) { + player.faceFrame = 0; + } + player.faceCount = 0; + } + + if (player.health) { + if (player.faceGotGun) { + pic = 22; + } else { + var h = player.health; + if (h > 100) { + h = 100; + } + if (h < 0) { + h = 0; + } + pic = (3*((100-h)/16)>>0) + player.faceFrame; + + //gsh + if ((player.flags & Wolf.FL_GODMODE)) { + pic = 23 + player.faceFrame; + } + } + } else { + pic = 21; + } + + $("#game .hud .bj").css({ + backgroundPosition : - (pic * Wolf.HUD_FACE_WIDTH) + "px 0" + }); + } + + + /** + * @description Update the FPS counter + * @private + */ + function updateFPS() { + var now = (new Date).getTime(), + dt = (now - lastFPSTime) / 1000, + frames = frameNum - lastFrame; + + lastFPSTime = now; + lastFrame = frameNum; + + $("#game .fps").html((frames / dt).toFixed(2)); + } + + /** + * @description Initiate the rendering cycle + * @private + * @param {object} game The game object + */ + function startRenderCycle(game) { + // cancel existing render cycle + if (hndRender) { + cancelAnimationFrame(hndRender); + hndRender = 0; + } + + /* + if (!hndFps) { + hndFps = setInterval(updateFPS, 1000); + } + $("#game .fps").show(); + */ + + Wolf.Renderer.init(); + + $("#game .renderer").show(); + + function nextFrame() { + if (!rendering) { + return; + } + if (!paused) { + updateScreen(game); + } + hndRender = requestAnimationFrame(nextFrame); + frameNum++; + } + rendering = true; + nextFrame(); + } + + + /** + * @description Start playing the specified level of the specified episode. + * @memberOf Wolf.Game + * @param {object} game The game object. + * @param {number} episodeNum The episode number. + * @param {number} levelNum The level number. + */ + function startLevel(game, episodeNum, levelNum) { + if (!Wolf.Episodes[episodeNum].enabled) { + return; + } + + playing = false; + rendering = false; + + game.episodeNum = episodeNum; + game.levelNum = levelNum; + + var episode = Wolf.Episodes[game.episodeNum]; + + Wolf.Level.load(episode.levels[game.levelNum].file, function(error, level) { + if (error) { + throw error; + } + + $("#game .renderer .floor").css({ + "background-color" : "rgb(" + + level.floor[0] + "," + + level.floor[1] + "," + + level.floor[2] + ")" + }); + + $("#game .renderer .ceiling").css({ + "background-color" : "rgb(" + + level.ceiling[0] + "," + + level.ceiling[1] + "," + + level.ceiling[2] + ")" + }); + + + game.level = level; + + levelMusic = level.music; + + Wolf.Level.scanInfoPlane(level, game.skill); // Spawn items/guards + + /* + game.player.position.x = 1944862; + game.player.position.y = 2156427; + game.player.angle = 8507; + */ + + $("#game .loading").show(); + + preloadLevelAssets(level, function() { + + Wolf.Sound.startMusic(level.music); + + game.player = Wolf.Player.spawn(level.spawn, level, game.skill, game.player); + + game.player.startScore = game.player.score; + + level.state.startTime = (new Date).getTime(); + level.state.elapsedTime = 0; + + playing = true; + startGameCycle(game); + startRenderCycle(game); + Wolf.Input.reset(); + Wolf.Input.lockPointer(); + + $("#game .loading").hide(); + $("#game").focus(); + $("#game .renderer .player-weapon").show(); + keyInputActive = true; + }); + + }); + } + + /** + * @description Preload the music and textures for the specified level + * @private + * @param {object} level The level object + * @param {function} callback Called when all files have loaded. + */ + function preloadLevelAssets(level, callback) { + var files = [], + tx, ty, texture, x, y, f, i, numFiles, + texturePath = "art/walls-shaded/" + Wolf.TEXTURERESOLUTION + "/", + spritePath = "art/sprites/" + Wolf.TEXTURERESOLUTION + "/"; + + function addTexture(texture) { + if (texture > 0) { + if (texture % 2 == 0) { + texture--; + } + f = texturePath + "w_" + texture + ".png"; + if (!preloadTextures[f]) { + files.push(f); + preloadTextures[f] = true; + } + } + } + + for (x=0;x<64;++x) { + for (y=0;y<64;++y) { + addTexture(level.wallTexX[x][y]); + addTexture(level.wallTexY[x][y]); + } + } + + // static sprites + f = spritePath + "002_053.png"; + if (!preloadSprites[f]) { + files.push(f); + preloadSprites[f] = true + } + + /* + for (i=0;i> 0) : 0, + secretRatio = levelState.totalSecrets ? ((levelState.foundSecrets / levelState.totalSecrets * 100) >> 0) : 0, + treasureRatio = levelState.totalTreasure ? ((levelState.foundTreasure / levelState.totalTreasure * 100) >> 0) : 0, + time = levelState.elapsedTime + ((new Date).getTime() - levelState.startTime), + totalTime, i, + avgKill = 0, avgSecret = 0, avgTreasure = 0; + + playing = false; + + Wolf.Sound.startMusic("music/URAHERO.ogg"); + + $("#game .renderer").hide(); + $("#game .fps").hide(); + $("#game .intermission .digit").hide(); + $("#game .intermission").show(); + + $("#game .intermission .background").hide(); + $("#game .intermission .background-secret").hide(); + $("#game .intermission .background-victory").hide(); + $("#game .intermission .stat").hide(); + $("#game .intermission .victory-stat").hide(); + $("#game .intermission .bj").hide(); + + // 99 mins max + time = Math.min(99*60, Math.round(time / 1000)); + + killRatio = Math.min(killRatio, 100); + secretRatio = Math.min(secretRatio, 100); + treasureRatio = Math.min(treasureRatio, 100); + + game.killRatios.push(killRatio); + game.secretRatios.push(secretRatio); + game.treasureRatios.push(treasureRatio); + game.totalTime += time; + + // secret level + if (game.levelNum == 9) { + $("#game .intermission .background-secret").show(); + $("#game .intermission .bj").show(); + bonus = 15000; + + // boss level + } else if (game.levelNum == 8) { + $("#game .intermission .background-victory").show(); + $("#game .intermission .victory-stat").show(); + + totalTime = Math.min(99*60, game.totalTime); + for (i=0;i> 0, true); + setIntermissionNumber("total-time-seconds", ((totalTime / 60) % 1) * 60, true); + + setIntermissionNumber("avg-kill-ratio", avgKill, false); + setIntermissionNumber("avg-secret-ratio", avgSecret, false); + setIntermissionNumber("avg-treasure-ratio", avgTreasure, false); + + // regular level + } else { + $("#game .intermission .background").show(); + $("#game .intermission .bj").show(); + $("#game .intermission .stat").show(); + + + if (parTime && parTime > time) { + bonus += (parTime - time) * parBonusAmount; + } + if (killRatio == 100) { + bonus += ratioBonusAmount; + } + if (secretRatio == 100) { + bonus += ratioBonusAmount; + } + if (treasureRatio == 100) { + bonus += ratioBonusAmount; + } + + time = time / 60; + parTime = parTime / 60; + + setIntermissionNumber("floor", game.levelNum + 1, false); + + setIntermissionNumber("bonus", bonus, false); + + setIntermissionNumber("time-minutes", time >> 0, true); + setIntermissionNumber("time-seconds", (time % 1) * 60, true); + + setIntermissionNumber("par-minutes", parTime >> 0, true); + setIntermissionNumber("par-seconds", (parTime % 1) * 60, true); + + setIntermissionNumber("kill-ratio", killRatio, false); + setIntermissionNumber("secret-ratio", secretRatio, false); + setIntermissionNumber("treasure-ratio", treasureRatio, false); + + } + + function anim() { + var now = (new Date).getTime(), + bjFrame = Math.floor(now / 500) % 2; + + $("#game .intermission .bj").css({ + backgroundPosition : - (162 * bjFrame) + "px 0px" + }); + intermissionAnim = requestAnimationFrame(anim); + } + + if (game.levelNum != 8) { + if (!intermissionAnim) { + anim(); + } + } + + function exitIntermission() { + if (intermissionAnim) { + cancelAnimationFrame(intermissionAnim); + intermissionAnim = 0; + } + $(document).off("keydown", progress); + $("#game .intermission").hide(); + } + + function progress(e) { + var nextLevel; + if (!$("#game .intermission").is(":visible")) { + exitIntermission(); + return; + } + if (e.keyCode == 13 || e.keyCode == 32) { + exitIntermission(); + if (game.player.playstate == Wolf.ex_secretlevel) { + nextLevel = 9; + } else { + if (game.levelNum == 8) { // Level was boss level - end of episode. + $("#game").fadeOut(1000, function() { + startVictoryText(game); + }); + return; + } else if (game.levelNum == 9) { // Level was secret level - go to previous level + 1 + // yuck + switch (game.episodeNum) { + case 0: nextLevel = 1; break; + case 1: nextLevel = 1; break; + case 2: nextLevel = 7; break; + case 3: nextLevel = 3; break; + case 4: nextLevel = 4; break; + case 5: nextLevel = 3; break; + default: nextLevel = game.levelNum + 1; break; + } + } else { + nextLevel = game.levelNum + 1; + } + } + Wolf.Player.givePoints(game.player, bonus); + startLevel(game, game.episodeNum, nextLevel); + } + } + + $(document).on("keydown", progress); + } + + + /** + * @description Update an intermission screen stat. + * @private + * @param {object} name The name (and CSS class) of the stat + * @param {number} value The value. + * @param {boolean} zeros If true, leading zeros are displayed. + */ + function setIntermissionNumber(name, value, zeros) { + var digits = $("#game .intermission ." + name + " .digit"), + i, digit, v; + for (i=0;i<10;i++) { + digits.removeClass("num-" + i); + } + value = value >> 0; + v = value; + for (i=0;i 0 || zeros || (value == 0 && i == 0)) { + digits.eq(digits.length - 1 - i).addClass("num-" + digit); + } + v = (v / 10) >> 0; + } + digits.show(); + } + + + /** + * @description Start red damage flash. + * @memberOf Wolf.Game + */ + function startDamageFlash() { + $("#game .renderer .damage-flash").show().fadeOut(300); + } + + /** + * @description Start bonus flash. + * @memberOf Wolf.Game + */ + function startBonusFlash() { + $("#game .renderer .bonus-flash").show().fadeOut(300); + } + + /** + * @description Show a notification. + * @memberOf Wolf.Game + * @param {string} text The notification + */ + function notify(text) { + Wolf.log(text); + } + + /** + * @description Query fullscreen. + * @memberOf Wolf.Game + * @returns boolean True if browser is in fullscreen mode, otherwise false. + */ + function isFullscreen() { + if ("webkitIsFullScreen" in document) { + return document.webkitIsFullScreen; + } else if ("mozFullScreen" in document) { + return document.mozFullScreen; + } else if ($("#main").data("scale") > 1) { + return true; + } + return false; + } + + /** + * @description Fullscreen event handler. + * @private + * @param {object} e Event object. + */ + function fullscreenChange(e) { + if (isFullscreen()) { + enterFullscreen(); + } else { + exitFullscreen(); + } + } + + /** + * @description Toggle the fullscreen state + * @private + */ + function toggleFullscreen() { + var main = $("#main")[0], + ret = false; + if (isFullscreen()) { + if (document.exitFullscreen) { + document.exitFullscreen(); + return true; + } else if (document.webkitCancelFullscreen) { + document.webkitCancelFullscreen(); + return true; + } else if (document.mozCancelFullscreen) { + document.mozCancelFullscreen(); + return true; + } + } else { + if (main.requestFullScreenWithKeys) { + main.requestFullScreenWithKeys(); + return true; + } else if (main.requestFullScreen) { + main.requestFullScreen(true); + return true; + } else if (main.webkitRequestFullScreen) { + main.webkitRequestFullScreen(true); + return true; + } else if (document.body.mozRequestFullScreenWithKeys) { + document.body.mozRequestFullScreenWithKeys(); + return true; + } else if (document.body.mozRequestFullScreen) { + document.body.mozRequestFullScreen(); + return true; + } + } + return false; + } + + + /** + * @description Scale the game to fit fullscreen mode + * @private + */ + function enterFullscreen() { + var ratio = window.innerWidth / 640, + sliceZoom = Math.floor(Wolf.SLICE_WIDTH * ratio), + zoom = sliceZoom / Wolf.SLICE_WIDTH, + transform = "scale(" + zoom + ")"; + + $("#main").css({ + "transform" : transform, + "-webkit-transform" : transform, + "-moz-transform" : transform, + "-ms-transform" : transform, + "-o-transform" : transform + }).data("scale", zoom); + } + + /** + * @description Scale the game to fit windowed mode + * @private + */ + function exitFullscreen() { + $("#main").css({ + "transform" : "", + "-webkit-transform" : "", + "-moz-transform" : "", + "-ms-transform" : "", + "-o-transform" : "" + }).data("scale", 1); + } + + + /** + * @description Initialize the game module + * @memberOf Wolf.Game + */ + function init() { + $(document) + .on("mozfullscreenchange", fullscreenChange) + .on("webkitfullscreenchange", fullscreenChange) + .on("fullscreenchange", fullscreenChange); + + Wolf.Input.bindKey("F11", function(e) { + if (!keyInputActive) { + return; + } + if (toggleFullscreen()) { + e.preventDefault(); + } else { + if (isFullscreen()) { + exitFullscreen(); + } else { + enterFullscreen(); + } + } + }); + + Wolf.Input.bindKey("P", function(e) { + if (!keyInputActive) { + return; + } + togglePause(); + }); + + Wolf.Input.bindKey("ESC", function(e) { + if (!keyInputActive) { + return; + } + exitToMenu(); + }); + + if (!isFullscreen() && (window.fullScreen || (window.innerWidth == screen.width && window.innerHeight == screen.height))) { + toggleFullscreen(); + } + } + + /** + * @description Exit to main menu + * @memberOf Wolf.Game + */ + function exitToMenu() { + if (!paused) { + togglePause(); + } + $("#game").hide(); + keyInputActive = false; + Wolf.Menu.show("main"); + } + + /** + * @description Resume game after coming from menu + * @memberOf Wolf.Game + */ + function resume() { + $("#game").show(); + if (paused) { + togglePause(); + } + keyInputActive = true; + if (levelMusic) { + Wolf.Sound.startMusic(levelMusic); + } + } + + + /** + * @description Query the game state + * @memberOf Wolf.Game + * @returns {boolean} True if the is currently playing + */ + function isPlaying() { + return playing; + } + + + /** + * @description Toggle the pause state. + * @private + */ + function togglePause() { + paused = !paused; + if (paused) { + Wolf.Sound.pauseMusic(true); + } else { + Wolf.Sound.pauseMusic(false); + lastTimeCount = (new Date).getTime(); + } + $("#game .renderer div.pause.overlay").toggle(paused); + } + + + function enableMouse(enable) { + mouseEnabled = enable; + } + function isMouseEnabled() { + return mouseEnabled; + } + + function getControls() { + var c = {}; + for (var a in controls) { + if (controls.hasOwnProperty(a)) { + c[a] = controls[a]; + } + } + return c; + } + + function bindControl(action, keys) { + controls[action] = keys; + } + + /* + function dump() { + console.log(currentGame); + window.open("data:text/plain," + JSON.stringify(currentGame), "dump"); + } + + function debugGodMode(enable) { + if (currentGame && currentGame.player) { + if (enable) { + currentGame.player.flags |= Wolf.FL_GODMODE; + } else { + currentGame.player.flags &= ~Wolf.FL_GODMODE; + } + Wolf.log("God mode " + (enable ? "enabled" : "disabled")); + } + } + + function debugNoTarget(enable) { + if (currentGame && currentGame.player) { + if (enable) { + currentGame.player.flags |= Wolf.FL_NOTARGET; + } else { + currentGame.player.flags &= ~Wolf.FL_NOTARGET; + } + Wolf.log("No target " + (enable ? "enabled" : "disabled")); + } + } + + function debugVictory() { + if (currentGame && currentGame.player) { + Wolf.log("Winning!"); + Wolf.Game.startIntermission(currentGame); + } + } + + function debugEndEpisode() { + if (currentGame && currentGame.player) { + victory(currentGame); + } + } + + function debugToggleAI(enable) { + processAI = !!enable; + } + + function debugGiveAll() { + if (currentGame && currentGame.player) { + Wolf.Player.givePoints(currentGame.player, 10000); + Wolf.Player.giveHealth(currentGame.player, 100, 100); + Wolf.Player.giveKey(currentGame.player, 0); + Wolf.Player.giveKey(currentGame.player, 1); + Wolf.Player.giveWeapon(currentGame.player, 2); + Wolf.Player.giveWeapon(currentGame.player, 3); + Wolf.Player.giveAmmo(currentGame.player, Wolf.AMMO_BULLETS, 99); + Wolf.log("Giving keys, weapons, ammo, health and 10000 points"); + } + } + */ + + return { + startGame : startGame, + startLevel : startLevel, + startIntermission : startIntermission, + startDamageFlash : startDamageFlash, + startBonusFlash : startBonusFlash, + enableMouse : enableMouse, + isMouseEnabled : isMouseEnabled, + isPlaying : isPlaying, + notify : notify, + isFullscreen : isFullscreen, + init : init, + getControls : getControls, + bindControl : bindControl, + resume : resume, + victory : victory, + endEpisode : endEpisode + + /* + dump : dump, + debugGodMode : debugGodMode, + debugNoTarget : debugNoTarget, + debugToggleAI : debugToggleAI, + debugGiveAll : debugGiveAll, + debugVictory : debugVictory, + debugEndEpisode : debugEndEpisode + */ + }; + +})(); \ No newline at end of file diff --git a/js/input.js b/js/input.js new file mode 100644 index 0000000..fd215c5 --- /dev/null +++ b/js/input.js @@ -0,0 +1,359 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +/** + * @namespace + * @description Functions for capturing keyboard/mouse input + */ +Wolf.Input = (function() { + + var keys, + lmbDown = false, + rmbDown = false, + bindings = [], + hasFocus = false, + mouseX = -1, mouseY = -1, + mouseMoveX = 0, mouseMoveY = 0; + + function init() { + var game = $("#game"), + main = $("#main"), + renderer = $("#game .renderer"); + + if (!keys) { + keys = []; + + $(document) + .on("keydown", function(e) { + e.preventDefault(); + + if (!Wolf.Game.isPlaying()) { + return; + } + + keys[e.keyCode] = true; + if (bindings[e.keyCode]) { + for (var i=0,n=bindings[e.keyCode].length;i 1 || mouseY < 0 || mouseY > 1) { + return null; + } else { + return { + x : (mouseX - 0.5) * 2, + y : (mouseY - 0.5) * 2 + }; + } + } + + function getMouseMovement() { + var x = mouseMoveX, + y = mouseMoveY; + mouseMoveX = 0; + mouseMoveY = 0; + return { + x : x / screen.width, + y : y / screen.height + }; + } + + function getPointer() { + var pointer = navigator.pointer || + navigator.webkitPointer || + navigator.mozPointer || + navigator.msPointer || + navigator.oPointer; + return pointer; + } + + function isPointerLocked() { + var pointer = getPointer(); + return pointer && pointer.isLocked && pointer.isLocked(); + } + + function lockPointer() { + var pointer = getPointer(); + if (!pointer) { + return; + } + + if (Wolf.Game.isFullscreen()) { + pointer.lock($("#game")[0], + function(e) { + Wolf.log("Pointer locked") + }, function(e) { + Wolf.log("Could not lock pointer: " + e); + } + ); + } + } + + function unlockPointer() { + var pointer = getPointer(); + if (!pointer) { + return; + } + pointer.unlock($("#game")[0]); + } + + + return { + init : init, + reset : reset, + resetMouse : resetMouse, + checkKeys : checkKeys, + clearKeys : clearKeys, + bindKey : bindKey, + leftMouseDown : leftMouseDown, + rightMouseDown : rightMouseDown, + getMouseCoords : getMouseCoords, + getMouseMovement : getMouseMovement, + isPointerLocked : isPointerLocked, + lockPointer : lockPointer, + unlockPointer : unlockPointer + }; + +})(); + + +Wolf.Keys = { + LEFT : 37, + UP : 38, + RIGHT : 39, + DOWN : 40, + ENTER : 13, + SPACE : 32, + SHIFT : 16, + CTRL : 17, + ALT : 18, + ESC : 27, + HOME : 36, + END : 35, + DEL : 46, + INS : 45, + PGUP : 33, + PGDN : 34, + SLASH : 111, + MINUS : 109, + PLUS : 107, + COMMA : 188, + PERIOD : 190, + 1 : 49, + 2 : 50, + 3 : 51, + 4 : 52, + 5 : 53, + 6 : 54, + 7 : 55, + 8 : 56, + 9 : 57, + 0 : 58, + A : 65, + B : 66, + C : 67, + D : 68, + E : 69, + F : 70, + G : 71, + H : 72, + I : 73, + J : 74, + K : 75, + L : 76, + M : 77, + N : 78, + O : 79, + P : 80, + Q : 81, + R : 82, + S : 83, + T : 84, + U : 85, + V : 86, + W : 87, + X : 88, + Y : 89, + Z : 90, + F1 : 112, + F2 : 113, + F3 : 114, + F4 : 115, + F5 : 116, + F6 : 117, + F7 : 118, + F8 : 119, + F9 : 120, + F10 : 121, + F11 : 122, + F12 : 123 +}; \ No newline at end of file diff --git a/js/level.js b/js/level.js new file mode 100644 index 0000000..650636a --- /dev/null +++ b/js/level.js @@ -0,0 +1,1134 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Level management + */ +Wolf.Level = (function() { + + Wolf.setConsts({ + WALL_TILE : 1, + PUSHWALL_TILE : (1 << 20), + DOOR_TILE : 2, + SECRET_TILE : 4, + DRESS_TILE : 8, + BLOCK_TILE : 16, + ACTOR_TILE : 32, + DEADACTOR_TILE : 64, + POWERUP_TILE : 128, + AMBUSH_TILE : 256, + EXIT_TILE : 512, + SECRETLEVEL_TILE : 1024, + ELEVATOR_TILE : (1 << 11), + + MAPHEADER_SIZE : 49, + MAP_SIGNATURE : 0x21444921, + + TILE_IS_E_TURN : (1 << 12), + TILE_IS_NE_TURN : (1 << 13), + TILE_IS_N_TURN : (1 << 14), + TILE_IS_NW_TURN : (1 << 15), + TILE_IS_W_TURN : (1 << 16), + TILE_IS_SW_TURN : (1 << 17), + TILE_IS_S_TURN : (1 << 18), + TILE_IS_SE_TURN : (1 << 19), + + MAX_POWERUPS : 1000 + }); + Wolf.setConsts({ + SOLID_TILE : (Wolf.WALL_TILE | Wolf.BLOCK_TILE | Wolf.PUSHWALL_TILE), + BLOCKS_MOVE_TILE : (Wolf.WALL_TILE | Wolf.BLOCK_TILE | Wolf.PUSHWALL_TILE | Wolf.ACTOR_TILE), + WAYPOINT_TILE : (Wolf.TILE_IS_E_TURN | Wolf.TILE_IS_NE_TURN | Wolf.TILE_IS_N_TURN | Wolf.TILE_IS_NW_TURN | + Wolf.TILE_IS_W_TURN | Wolf.TILE_IS_SW_TURN | Wolf.TILE_IS_S_TURN | Wolf.TILE_IS_SE_TURN ) + }); + + var statinfo = [ + [false, -1], // puddle spr1v + [ true, -1], // Green Barrel " + [ true, -1], // Table/chairs " + [ true, -1], // Floor lamp " + [false, -1], // Chandelier " + [ true, -1], // Hanged man " + [false, Wolf.pow_alpo], // Bad food " + [ true, -1], // Red pillar " + [ true, -1], // Tree spr2v + [false, -1], // Skeleton flat " + [ true, -1], // Sink " (SOD:gibs) + [ true, -1], // Potted plant " + [ true, -1], // Urn " + [ true, -1], // Bare table " + [false, -1], // Ceiling light " + [false, -1], // Kitchen stuff " + [ true, -1], // suit of armor spr3v + [ true, -1], // Hanging cage " + [ true, -1], // SkeletoninCage " + [false, -1], // Skeleton relax " + [false, Wolf.pow_key1], // Key 1 " + [false, Wolf.pow_key2], // Key 2 " + [ true, -1], // stuff (SOD:gibs) + [false, -1], // stuff + [false, Wolf.pow_food], // Good food spr4v + [false, Wolf.pow_firstaid], // First aid " + [false, Wolf.pow_clip], // Clip " + [false, Wolf.pow_machinegun], // Machine gun " + [false, Wolf.pow_chaingun], // Gatling gun " + [false, Wolf.pow_cross], // Cross " + [false, Wolf.pow_chalice], // Chalice " + [false, Wolf.pow_bible], // Bible " + [false, Wolf.pow_crown], // crown spr5v + [false, Wolf.pow_fullheal], // one up " + [false, Wolf.pow_gibs], // gibs " + [ true, -1], // barrel " + [ true, -1], // well " + [ true, -1], // Empty well " + [false, Wolf.pow_gibs], // Gibs 2 " + [ true, -1], // flag " + [ true, -1], // Call Apogee spr7v + [false, -1], // junk " + [false, -1], // junk " + [false, -1], // junk " + [false, -1], // pots " + [ true, -1], // stove " (SOD:gibs) + [ true, -1], // spears " (SOD:gibs) + [false, -1] // vines " + ]; + + for (var i=0;i= 0x5A && layer1 <= 0x5F) || layer1 == 0x64 || layer1 == 0x65) { // door + level.tileMap[x][y] |= Wolf.DOOR_TILE; + Wolf.Doors.spawn(level, x, y, layer1); + level.areas[x][y] = -2; // door area + } else { + level.tileMap[x][y] |= Wolf.WALL_TILE; + level.wallTexX[x][y] = (layer1-1) * 2 + 1; + level.wallTexY[x][y] = (layer1-1) * 2; + level.areas[x][y] = -1; // wall area + if (layer1 == 0x15) { // elevator + level.tileMap[x][y] |= Wolf.ELEVATOR_TILE; + } + } + } else if (layer1 == 0x6a) { // Ambush floor tile + level.tileMap[x][y] |= Wolf.AMBUSH_TILE; + level.areas[x][y] = -3; // unknown area + } else if (layer1 >= Wolf.FIRSTAREA && layer1 < (Wolf.FIRSTAREA + Wolf.NUMAREAS)) { // area + if (layer1 == Wolf.FIRSTAREA) { // secret level + level.tileMap[x][y] |= Wolf.SECRETLEVEL_TILE; + } + level.areas[x][y] = layer1 - Wolf.FIRSTAREA;// spawn area + } else { + level.areas[x][y] = -3; // unknown area + } + // End of the map data layer + } + } + + + // JDC: try to replace all the unknown areas with an adjacent area, to + // avoid the silent attack / no damage problem when you get an ambush + // guard stuck on their original tile + for (x=1;x<63;x++) { + for (y=1;y<63;y++) { + if (level.areas[x][y] != -3) { + continue; + } + if (level.areas[x-1][y] >= 0) { + level.areas[x][y] = level.areas[x-1][y]; + } else if (level.areas[x+1][y] >= 0) { + level.areas[x][y] = level.areas[x+1][y]; + } else if (level.areas[x][y-1] >= 0) { + level.areas[x][y] = level.areas[x][y-1]; + } else if (level.areas[x+1][y+1] >= 0) { + level.areas[x][y] = level.areas[x][y+1]; + } + } + } + + Wolf.Doors.setAreas(level); + + return level; + } + + /** + * @description Read plane data from map data + * @private + * @param {object} file The file object + * @param {number} offset The starting position + * @param {number} length The length of the plane data + * @param {number} rle The RLE tag + * @returns {array} The plane data + */ + function readPlaneData(file, offset, length, rle) { + file.position = offset; + + var expandedLength = Wolf.File.readUInt16(file), + carmackData = Wolf.File.readBytes(file, length - 2), + expandedData = carmackExpand(carmackData, expandedLength); + + return rlewExpand(expandedData.slice(1), 64*64*2, rle); + } + + + /** + * @description Expand RLE data + * @private + * @param {array} source The source data + * @param {number} length The length of the expanded data + * @param {number} rlewtag The RLE tag + * @returns {array} The expanded data + */ + function rlewExpand(source, length, rlewtag) { + var value, + count, + i, + end, /* W16 */ + inptr = 0, + outptr = 0, + dest = []; + + end = outptr + (length >> 1); + + do { + value = source[inptr++]; + if (value != rlewtag) { + // uncompressed + dest[outptr++] = value; + } else { + // compressed string + count = source[inptr++]; + value = source[inptr++]; + for (i=1;i<=count;++i) { + dest[outptr++] = value; + } + } + } while (outptr < end); + + return dest; + } + + /** + * @description Expand Carmackized data + * @private + * @param {array} source The source data + * @param {number} length The length of the expanded data + * @returns {array} The expanded data + */ + function carmackExpand(source, length) { + var NEARTAG = 0xA7, + FARTAG = 0xA8; + + var chhigh, offset, /* W32 */ + copyptr, outptr, /* W16 */ + inptr, /* W8 */ + ch, count, /* W16 */ + dest; + + length /= 2; + + inptr = 0; + outptr = 0; + dest = []; + + function W16(b, i) { + return b[i] + (b[i+1] << 8); + } + + while (length) { + ch = source[inptr] + (source[inptr+1] << 8); + //ch = W16(source, inptr); + inptr += 2; + chhigh = ch >> 8; + if (chhigh == NEARTAG) { + count = ch & 0xff; + if (!count) { + // have to insert a word containing the tag byte + ch |= source[inptr++]; + dest[outptr++] = ch; + length--; + } else { + offset = source[inptr++]; + copyptr = outptr - offset; + length -= count; + while (count--) { + dest[outptr++] = dest[copyptr++]; + } + } + } else if (chhigh == FARTAG) { + count = ch & 0xff; + if (!count) { + // have to insert a word containing the tag byte + ch |= source[inptr++]; + dest[outptr++] = ch; + length--; + } else { + offset = source[inptr] + (source[inptr+1] << 8); + //offset = W16(source, inptr); + inptr += 2; + copyptr = offset; + length -= count; + while (count--) { + dest[outptr++] = dest[copyptr++]; + } + } + } else { + dest[outptr++] = ch; + length--; + } + } + return dest; + } + + /** + * @description Load level data + * @memberOf Wolf.Level + * @param {string} filename The name of the level file. + * @param {function} callback Called with the resulting level object. + * @returns {object} The level object. + */ + function load(filename, callback) { + Wolf.File.open(filename, Wolf.MapData, function(error, file) { + var level; + if (error) { + callback(error); + } + try { + level = parseMapData(file); + } catch(error) { + callback(error); + return; + } + callback(null, level); + }); + } + + function reload(level) { + return parseMapData(level.file); + } + + + /** + * @description Spawn an object in the level at the specified position. + * @private + * @param {object} level The level object. + * @param {number} type The object type. + * @param {number} x The x coordinate. + * @param {number} y The y coordinate. + */ + function spawnObj(level, type, x, y) { + if (type >= 23 && type < 23 + statinfo.length) { // static object + spawnStatic(level, type - 23, x, y); + return; + } + + switch (type) { + case 0x13: // start N + level.spawn.x = Wolf.TILE2POS(x); + level.spawn.y = Wolf.TILE2POS(y); + level.spawn.angle = Wolf.ANG_90; + break; + case 0x14: // start E + level.spawn.x = Wolf.TILE2POS(x); + level.spawn.y = Wolf.TILE2POS(y); + level.spawn.angle = Wolf.ANG_0; + break; + case 0x15: // start S + level.spawn.x = Wolf.TILE2POS(x); + level.spawn.y = Wolf.TILE2POS(y); + level.spawn.angle = Wolf.ANG_270; + break; + case 0x16: // start W + level.spawn.x = Wolf.TILE2POS(x); + level.spawn.y = Wolf.TILE2POS(y); + level.spawn.angle = Wolf.ANG_180; + break; + case 0x5a: // turn E + level.tileMap[x][y] |= Wolf.TILE_IS_E_TURN;//FIXME! + break; + case 0x5b: // turn NE + level.tileMap[x][y] |= Wolf.TILE_IS_NE_TURN;//FIXME! + break; + case 0x5c: // turn N + level.tileMap[x][y] |= Wolf.TILE_IS_N_TURN;//FIXME! + break; + case 0x5d: // turn NW + level.tileMap[x][y] |= Wolf.TILE_IS_NW_TURN;//FIXME! + break; + case 0x5e: // turn W + level.tileMap[x][y] |= Wolf.TILE_IS_W_TURN;//FIXME! + break; + case 0x5f: // turn SW + level.tileMap[x][y] |= Wolf.TILE_IS_SW_TURN;//FIXME! + break; + case 0x60: // turn S + level.tileMap[x][y] |= Wolf.TILE_IS_S_TURN;//FIXME! + break; + case 0x61: // turn SE + level.tileMap[x][y] |= Wolf.TILE_IS_SE_TURN;//FIXME! + break; + case 0x62: // pushwall modifier + level.tileMap[x][y] |= Wolf.SECRET_TILE; + level.state.totalSecrets++; + break; + case 0x63: // Victory trigger + level.tileMap[x][y] |= Wolf.EXIT_TILE; + break; + // spawn guards + } // end of switch( type ) + + } + + /** + * @description Spawn a static object at the specified position. + * @private + * @param {object} level The level object. + * @param {number} type The static object type. + * @param {number} x The x coordinate. + * @param {number} y The y coordinate. + */ + function spawnStatic(level, type, x, y) { + var sprite, pu; + + if (statinfo[type].powerup == -1 ) { + if (statinfo[type].block) { // blocking static + level.tileMap[x][y] |= Wolf.BLOCK_TILE; + } else { // dressing static + level.tileMap[x][y] |= Wolf.DRESS_TILE; + } + + sprite = Wolf.Sprites.getNewSprite(level); + if (!sprite) { + return; + } + + Wolf.Sprites.setPos(level, sprite, Wolf.TILE2POS(x), Wolf.TILE2POS(y), 0 ); + Wolf.Sprites.setTex(level, sprite, 0, Wolf.SPR_STAT_0 + type); + } else { + pu = statinfo[type].powerup; + Wolf.Powerups.spawn(level, x, y, pu); + + if (pu == Wolf.pow_cross || pu == Wolf.pow_chalice || pu == Wolf.pow_bible || pu == Wolf.pow_crown || pu == Wolf.pow_fullheal) { + level.state.totalTreasure++; // FIXME: move this to Powerup_Spawn Function! + } + } + } + + + + var cachedGuard = 0, + cachedOfficer = 0, + cachedSS = 0, + cachedDog = 0, + cachedMutant = 0, + progress_bar = 0; + + + /** + * @description Spawn all actors and mark down special places. + * @memberOf Wolf.Level + * @param {object} level The level object. + * @param {number} skill The difficulty level. + */ + function scanInfoPlane(level, skill) { + var x, y, tile; + + cachedGuard = 0; + cachedOfficer = 0; + cachedSS = 0; + cachedDog = 0; + cachedMutant = 0; + progress_bar = 0; + + for (y = 0;y < 64;++y) { + for (x = 0;x < 64;++x) { + tile = level.plane2[(63 - y) * 64 + x]; + if (!tile) { + continue; + } + + switch (tile) { + // guard + case 180: + case 181: + case 182: + case 183: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 144: + case 145: + case 146: + case 147: + if(skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 108: + case 109: + case 110: + case 111: + if (!cachedGuard) { + Wolf.Sprites.cacheTextures(Wolf.SPR_GRD_S_1, Wolf.SPR_GRD_SHOOT3); + cachedGuard = 1; + } + Wolf.Actors.spawnStand(level, skill, Wolf.en_guard, x, y, tile - 108); + break; + case 184: + case 185: + case 186: + case 187: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 148: + case 149: + case 150: + case 151: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 112: + case 113: + case 114: + case 115: + if (!cachedGuard) { + Wolf.Sprites.cacheTextures(Wolf.SPR_GRD_S_1, Wolf.SPR_GRD_SHOOT3); + cachedGuard = 1; + } + Wolf.Actors.spawnPatrol(level, skill, Wolf.en_guard, x, y, tile - 112); + break; + case 124: + Wolf.Actors.spawnDeadGuard(level, skill, Wolf.en_guard, x, y); + break; + // officer + case 188: + case 189: + case 190: + case 191: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 152: + case 153: + case 154: + case 155: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 116: + case 117: + case 118: + case 119: + if (!cachedOfficer) { + Wolf.Sprites.cacheTextures(Wolf.SPR_OFC_S_1,Wolf.SPR_OFC_SHOOT3); + cachedOfficer = 1; + } + Wolf.Actors.spawnStand(level, skill, Wolf.en_officer, x, y, tile - 116); + break; + case 192: + case 193: + case 194: + case 195: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 156: + case 157: + case 158: + case 159: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 120: + case 121: + case 122: + case 123: + if (!cachedOfficer) { + Wolf.Sprites.cacheTextures(Wolf.SPR_OFC_S_1, Wolf.SPR_OFC_SHOOT3); + cachedOfficer = 1; + } + Wolf.Actors.spawnPatrol(level, skill, Wolf.en_officer, x, y, tile - 120); + break; + // SS + case 198: + case 199: + case 200: + case 201: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 162: + case 163: + case 164: + case 165: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 126: + case 127: + case 128: + case 129: + if (!cachedSS) { + Wolf.Sprites.cacheTextures(Wolf.SPR_SS_S_1, Wolf.SPR_SS_SHOOT3); + cachedSS = 1; + } + Wolf.Actors.spawnStand(level, skill, Wolf.en_ss, x, y, tile - 126); + break; + case 202: + case 203: + case 204: + case 205: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 166: + case 167: + case 168: + case 169: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 130: + case 131: + case 132: + case 133: + if (!cachedSS) { + Wolf.Sprites.cacheTextures(Wolf.SPR_SS_S_1, Wolf.SPR_SS_SHOOT3); + cachedSS = 1; + } + Wolf.Actors.spawnPatrol(level, skill, Wolf.en_ss, x, y, tile - 130); + break; + // dogs + case 206: + case 207: + case 208: + case 209: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 170: + case 171: + case 172: + case 173: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 134: + case 135: + case 136: + case 137: + if (!cachedDog) { + Wolf.Sprites.cacheTextures(Wolf.SPR_DOG_W1_1, Wolf.SPR_DOG_JUMP3); + cachedDog = 1; + } + Wolf.Actors.spawnStand(level, skill, Wolf.en_dog, x, y, tile - 134); + break; + case 210: + case 211: + case 212: + case 213: + if (skill < Wolf.gd_hard) { + break; + } + tile -= 36; + case 174: + case 175: + case 176: + case 177: + if (skill < Wolf.gd_medium) { + break; + } + tile -= 36; + case 138: + case 139: + case 140: + case 141: + if (!cachedDog) { + Wolf.Sprites.cacheTextures(Wolf.SPR_DOG_W1_1, Wolf.SPR_DOG_JUMP3); + cachedDog = 1; + } + Wolf.Actors.spawnPatrol(level, skill, Wolf.en_dog, x, y, tile - 138); + break; + // bosses + case 214: + Wolf.Sprites.cacheTextures(Wolf.SPR_BOSS_W1, Wolf.SPR_BOSS_DIE3); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_boss, x, y); + break; + case 197: + Wolf.Sprites.cacheTextures(Wolf.SPR_GRETEL_W1, Wolf.SPR_GRETEL_DIE3); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_gretel, x, y); + break; + case 215: + Wolf.Sprites.cacheTextures(Wolf.SPR_GIFT_W1, Wolf.SPR_GIFT_DEAD); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_gift, x, y); + break; + case 179: + Wolf.Sprites.cacheTextures(Wolf.SPR_FAT_W1, Wolf.SPR_FAT_DEAD); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_fat, x, y); + break; + case 196: + Wolf.Sprites.cacheTextures(Wolf.SPR_SCHABB_W1, Wolf.SPR_HYPO4); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_schabbs, x, y); + break; + case 160: + Wolf.Sprites.cacheTextures(Wolf.SPR_FAKE_W1, Wolf.SPR_FAKE_DEAD); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_fake, x, y); + break; + case 178: + Wolf.Sprites.cacheTextures(Wolf.SPR_MECHA_W1, Wolf.SPR_HITLER_DIE7); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_mecha, x, y); + break; + // Spear + case 106: + Wolf.Sprites.cacheTextures(Wolf.SPR_SPECTRE_W1, Wolf.SPR_SPECTRE_F4); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_spectre, x, y); + break; + case 107: + Wolf.Sprites.cacheTextures(Wolf.SPR_ANGEL_W1, Wolf.SPR_ANGEL_DEAD); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_angel, x, y); + break; + case 125: + Wolf.Sprites.cacheTextures(Wolf.SPR_TRANS_W1, Wolf.SPR_TRANS_DIE3); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_trans, x, y); + break; + case 142: + Wolf.Sprites.cacheTextures(Wolf.SPR_UBER_W1, Wolf.SPR_UBER_DEAD); + Wolf.Actors.spawnBoss(level, skill, olf.en_uber, x, y); + break; + case 143: + Wolf.Sprites.cacheTextures(Wolf.SPR_WILL_W1, Wolf.SPR_WILL_DEAD); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_will, x, y); + break; + case 161: + Wolf.Sprites.cacheTextures(Wolf.SPR_DEATH_W1, Wolf.SPR_DEATH_DEAD); + Wolf.Actors.spawnBoss(level, skill, Wolf.en_death, x, y); + break; + // mutants + case 252: + case 253: + case 254: + case 255: + if (skill < Wolf.gd_hard) + break; + tile -= 18; + case 234: + case 235: + case 236: + case 237: + if (skill < Wolf.gd_medium) + break; + tile -= 18; + case 216: + case 217: + case 218: + case 219: + if (!cachedMutant) { + Wolf.Sprites.cacheTextures(Wolf.SPR_MUT_S_1, Wolf.SPR_MUT_SHOOT4); + cachedMutant = 1; + } + Wolf.Actors.spawnStand(level, skill, Wolf.en_mutant, x, y, tile - 216); + break; + case 256: + case 257: + case 258: + case 259: + if (skill < Wolf.gd_hard) + break; + tile -= 18; + case 238: + case 239: + case 240: + case 241: + if (skill < Wolf.gd_medium ) + break; + tile -= 18; + case 220: + case 221: + case 222: + case 223: + if (!cachedMutant) { + Wolf.Sprites.cacheTextures(Wolf.SPR_MUT_S_1, Wolf.SPR_MUT_SHOOT4); + cachedMutant = 1; + } + Wolf.Actors.spawnPatrol(level, skill, Wolf.en_mutant, x, y, tile - 220 ); + break; + // ghosts + case 224: + Wolf.Sprites.cacheTextures(Wolf.SPR_BLINKY_W1, Wolf.SPR_BLINKY_W2); + Wolf.Actors.spawnGhosts(level, skill, Wolf.en_blinky, x, y); + break; + case 225: + Wolf.Sprites.cacheTextures(Wolf.SPR_PINKY_W1, Wolf.SPR_PINKY_W2); + Wolf.Actors.spawnGhosts(level, skill, Wolf.en_clyde, x, y); + break; + case 226: + Wolf.Sprites.cacheTextures(Wolf.SPR_CLYDE_W1, Wolf.SPR_CLYDE_W2); + Wolf.Actors.spawnGhosts(level, skill, Wolf.en_pinky, x, y); + break; + case 227: + Wolf.Sprites.cacheTextures(Wolf.SPR_INKY_W1, Wolf.SPR_INKY_W2); + Wolf.Actors.spawnGhosts(level, skill, Wolf.en_inky, x, y); + break; + } + } + } + } + + + /** + * @description Check if there is a clear line of sight between 2 points. + * @memberOf Wolf.Level + * @param {number} x1 The x coordinate of point 1. + * @param {number} y1 The y coordinate of point 1. + * @param {number} x2 The x coordinate of point 2. + * @param {number} y2 The y coordinate of point 2. + * @param {object} level The level object. + * @returns {boolean} True if a straight line between 2 points is unobstructed, otherwise false. + */ + function checkLine(x1, y1, x2, y2, level) { + var xt1, yt1, xt2, yt2, /* tile positions */ + x, y, /* current point in !tiles! */ + xdist, ydist, + xstep, ystep, /* Step value for each whole xy */ + + deltafrac, /* current point in !1/256 of tile! */ + + frac, /* Fractional xy stepper */ + + partial, /* how much to move in our direction to border */ + intercept, /* Temp for door code */ + + FRACBITS = 8; /* Number of bits of fraction */ + + // get start & end tiles + xt1 = x1 >> Wolf.TILESHIFT; + yt1 = y1 >> Wolf.TILESHIFT; + + xt2 = x2 >> Wolf.TILESHIFT; + yt2 = y2 >> Wolf.TILESHIFT; + + xdist = Math.abs(xt2 - xt1); // X distance in tiles + ydist = Math.abs(yt2 - yt1); // Y distance in tiles + + // 1/256 tile precision (TILESHIFT is 16) + x1 >>= FRACBITS; y1 >>= FRACBITS; + x2 >>= FRACBITS; y2 >>= FRACBITS; + + if (xdist) { // always positive check only for 0 + if (xt2 > xt1) { + partial = 256 - (x1 & 0xff); + xstep = 1; + } else { + partial = x1 & 0xff; + xstep = -1; + } + + deltafrac = Math.abs(x2 - x1); + ystep = ((y2 - y1) << FRACBITS) / deltafrac; + frac = y1 + ((ystep * partial) >> FRACBITS); + + x = xt1 + xstep; + xt2 += xstep; + do { + y = frac >> FRACBITS; + frac += ystep; + + // assert( x >= 0 && x < 64 && y >= 0 && y < 64 ); + if (level.tileMap[x][y] & Wolf.WALL_TILE) { + return false; // Wall is in path quitting! + } + + if (level.tileMap[x][y] & Wolf.DOOR_TILE ) { + // door, see if the door is open enough + if (level.state.doorMap[x][y].action != Wolf.dr_open) { + if (level.state.doorMap[x][y].action == Wolf.dr_closed) { + return false; + } + // checking vertical doors in action: ->_I_ + intercept = ((frac - ystep / 2) & 0xFF) >> 4; // 1/64 of tile + if (intercept < (63 - level.state.doorMap[x][y].ticcount)) { + return false; + } + } + } + x += xstep; + } while (x != xt2); + } + + if (ydist) { // always positive check only for 0 + if (yt2 > yt1) { + partial = 256 - (y1 & 0xff); + ystep = 1; + } else { + partial = y1 & 0xff; + ystep = -1; + } + + deltafrac = Math.abs(y2 - y1); + xstep = ((x2 - x1) << FRACBITS) / deltafrac; + frac = x1 + ((xstep * partial) >> FRACBITS); + + y = yt1 + ystep; + yt2 += ystep; + do { + x = frac >> FRACBITS; + frac += xstep; + + //assert( x >= 0 && x < 64 && y >= 0 && y < 64 ); + if (level.tileMap[x][y] & Wolf.WALL_TILE ) { + return false; // Wall is in path quitting! + } + + if (level.tileMap[x][y] & Wolf.DOOR_TILE) { + // door, see if the door is open enough + if (level.state.doorMap[x][y].action != Wolf.dr_open) { + if (level.state.doorMap[x][y].action == Wolf.dr_closed ) { + return false; + } + // checking vertical doors in action: ->_I_ + intercept = ((frac - xstep / 2) & 0xFF) >> 4; // 1/64 of tile + if (intercept < level.state.doorMap[x][y].ticcount) { + return false; + } + } + } + y += ystep; + } while (y != yt2); + } + return true; + } + + return { + load : load, + reload : reload, + scanInfoPlane : scanInfoPlane, + checkLine : checkLine + }; + +})(); \ No newline at end of file diff --git a/js/load.js b/js/load.js new file mode 100644 index 0000000..22c0d7b --- /dev/null +++ b/js/load.js @@ -0,0 +1,126 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +(function($) { + +// these files are preloaded while the title screen is showing +var files = [ + "js/requestanimframe.js", + + "js/wolf.js", + "js/random.js", + "js/angle.js", + "js/math.js", + "js/input.js", + "js/sound.js", + "js/menu.js", + "js/file.js", + "js/game.js", + "js/player.js", + "js/sprites.js", + "js/powerups.js", + "js/ai.js", + "js/actorai.js", + "js/actors.js", + "js/actstat.js", + "js/weapon.js", + "js/doors.js", + "js/pushwall.js", + "js/areas.js", + "js/level.js", + "js/raycaster.js", + "js/renderer.js", + + "js/episodes.js", + "js/maps.js", + + "preload!art/menubg_main.png", + "preload!art/menuitems.png", + "preload!art/menuselector.png" + +]; + +// these files are preloaded in the background after the menu is displayed. +// only non-essential files here +var files2 = [ + "preload!art/menubg_episodes.png", + "preload!art/menuitems_episodes.png", + "preload!art/menubg_skill.png", + "preload!art/menubg_levels.png", + "preload!art/menuitems_levels.png", + "preload!art/skillfaces.png", + "preload!art/getpsyched.png", + "preload!art/menubg_control.png", + "preload!art/menulight.png", + "preload!art/menubg_customize.png", + "preload!art/control_keys.png", + "preload!art/confirm_newgame.png", + "preload!art/paused.png" +]; + +$(document).ready(function() { + + var progress = $("
"), + n = 0; + + progress.addClass("load-progress").appendTo("#title-screen"); + $("#title-screen").show(); + + + yepnope.addPrefix("preload", function(resource) { + resource.noexec = true; + resource.instead = function(input, callback) { + var image = new Image(); + image.onload = callback; + image.onerror = callback; + image.src = input.substr(input.lastIndexOf("!")+1); + }; + return resource; + }); + + + Modernizr.load([ + { + load : files, + callback : function(file) { + progress.width((++n / files.length) * 100 + "%"); + }, + complete : function() { + progress.remove(); + $("#title-screen").fadeOut(1500, function() { + Wolf.Input.init(); + Wolf.Game.init(); + Wolf.Menu.show(); + }); + // preload non-essential art + Modernizr.load(files2); + } + } + ]); +}); + +})(jQuery); \ No newline at end of file diff --git a/js/maps.sample.js b/js/maps.sample.js new file mode 100644 index 0000000..61dadf7 --- /dev/null +++ b/js/maps.sample.js @@ -0,0 +1,37 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** + * @description Encoded map file data (Example) + * + * This file is a table of base64 encoded map data. + * Note: No actual data is included in this release. + */ + +Wolf.MapData = { + "maps/w00.map" : "... base64 encoded map file data here ...", + "maps/w01.map" : "... base64 encoded map file data here ..." +}; diff --git a/js/math.js b/js/math.js new file mode 100644 index 0000000..6010747 --- /dev/null +++ b/js/math.js @@ -0,0 +1,329 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Math functions and lookup tables + */ +Wolf.Math = (function() { + + // ------------------------- * LUTs * ------------------------- + var SinTable = [], // [ ANG_360 + ANG_90 + 1 ], + CosTable = [], // SinTable + ANG_90, + TanTable = [], //[ ANG_360 + 1 ]; + + XnextTable = [], //[ ANG_360 + 1 ], + YnextTable = [], //[ ANG_360 + 1 ], + + ColumnAngle = [], // [ 640 ]; // ViewAngle=PlayerAngle+ColumnAngle[curcolumn]; /in fines/ + + // Angle Direction Types & LUTs (Hard Coded! Please do not mess them) + q_first = 0, q_second = 1, q_third = 2, q_fourth = 3, // quadrant; + dir4_east = 0, dir4_north = 1, dir4_west = 2, dir4_south = 3, dir4_nodir = 4, // dir4type; + + dir8_east = 0, dir8_northeast = 1, dir8_north = 2, dir8_northwest = 3, dir8_west = 4, + dir8_southwest = 5, dir8_south = 6, dir8_southeast = 7, dir8_nodir = 8, // dir8type; + + dx4dir = [1, 0, -1, 0, 0], // dx & dy based on direction + dy4dir = [0, 1, 0, -1, 0], + dx8dir = [1, 1, 0, -1, -1, -1, 0, 1, 0], // dx & dy based on direction + dy8dir = [0, 1, 1, 1, 0, -1, -1, -1, 0], + opposite4 = [2, 3, 0, 1, 4], + opposite8 = [4, 5, 6, 7, 0, 1, 2, 3, 8], + dir4to8 = [0, 2, 4, 6, 8], + diagonal = [ + /* east */ [dir8_nodir, dir8_nodir, dir8_northeast, dir8_nodir, dir8_nodir, dir8_nodir, dir8_southeast, dir8_nodir, dir8_nodir], + [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], + /* north */ [dir8_northeast, dir8_nodir, dir8_nodir, dir8_nodir, dir8_northwest, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], + [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], + /* west */ [dir8_nodir, dir8_nodir, dir8_northwest, dir8_nodir, dir8_nodir, dir8_nodir, dir8_southwest, dir8_nodir, dir8_nodir], + [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], + /* south */ [dir8_southeast, dir8_nodir, dir8_nodir, dir8_nodir, dir8_southwest, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], + [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir], + [dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir, dir8_nodir] + ], + + // dir of delta tooks dx{-1|0|1}+1 & dy{-1|0|1}+1 and give direction + dir4d = [ + [dir4_nodir, dir4_west , dir4_nodir], + [dir4_south, dir4_nodir, dir4_north], + [dir4_nodir, dir4_east , dir4_nodir] + ], + 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]; + dir4angle = [Wolf.ANG_0, Wolf.ANG_90, Wolf.ANG_180, Wolf.ANG_270, Wolf.ANG_0]; + + + /** + * @private + * @description Build LUTs, etc. + */ + function buildTables() { + var angle, tanfov2, tanval, value, + n; + + for (n = 0; n <= Wolf.ANG_90 ; ++n) { + angle = Wolf.FINE2RAD(n); + value = Math.sin(angle); + SinTable[n] = SinTable[Wolf.ANG_180 - n] = SinTable[n + Wolf.ANG_360] = value; + SinTable[Wolf.ANG_180 + n] = SinTable[Wolf.ANG_360 - n] = -value; + } + + for (n = 0; n <= SinTable.length - Wolf.ANG_90; ++n) { + CosTable[n] = SinTable[n + Wolf.ANG_90]; + } + + for (n = 0; n <= Wolf.ANG_360 ; ++n) { + angle = Wolf.FINE2RAD(n); //angle is in radians, n is in FINEs + + if (n == Wolf.ANG_90 || n == Wolf.ANG_270) { + TanTable[n] = Math.tan(Wolf.FINE2RAD(n - 0.5)); // infinity + YnextTable[n] = (Wolf.FLOATTILE * Math.tan(Wolf.FINE2RAD(n - 0.5)))>>0; // infinity + } else { + TanTable[n] = Math.tan(angle); + YnextTable[n] = (Wolf.FLOATTILE * Math.tan(angle))>>0; + } + + if(n == Wolf.ANG_0 || n == Wolf.ANG_360) { + XnextTable[n] = (Wolf.FLOATTILE / Math.tan(Wolf.FINE2RAD(n + 0.5)))>>0; // infinity + } else if (n == Wolf.ANG_180) { + XnextTable[n] = (Wolf.FLOATTILE / Math.tan(Wolf.FINE2RAD(n - 0.5)))>>0; // -infinity + } else if (n == Wolf.ANG_90 || n == Wolf.ANG_270) { + XnextTable[n] = 0; + } else { + XnextTable[n] = (Wolf.FLOATTILE / Math.tan(angle))>>0; + } + } + + tanfov2 = (Math.tan(Wolf.DEG2RAD((calcFov(75, Wolf.XRES, Wolf.YRES) / 2.0)))) * (Wolf.XRES / Wolf.YRES); + for (n = 0; n < Wolf.XRES; ++n) { + tanval = tanfov2 * (-1.0 + 2.0 * n / (Wolf.XRES-1)); + ColumnAngle[n] = Wolf.RAD2FINE(Math.atan(tanval)) >> 0; + } + + Wolf.Random.init(1); // random number generators + + return 1; + } + + + /** + * @description Calculate the field of view. + * @memberOf Wolf.Math + * @param {number} fovX Must be within 1 and 179 degrees. + * @param {number} width Width of viewing area. + * @param {number} height Height of viewing area. + * @returns {number} The field of view in degrees. + */ + + function calcFov(fovX, width, height) { + if (fovX < 1 || fovX > 179) { + throw Error("Bad fov: " + fovX ); + } + + return Wolf.RAD2DEG(Math.atan(height / (width / Math.tan(fovX / 360 * Math.PI)))) * 2; + } + + + /** + * @description Clips angle to [0..360] bounds. + * @memberOf Wolf.Math + * @param {number} alpha Angle in degrees. + * @returns {number} Normalized angle. + */ + function normalizeAngle(alpha) { + if (alpha > Wolf.ANG_360) { + alpha %= Wolf.ANG_360; + } + if (alpha < Wolf.ANG_0) { + alpha = Wolf.ANG_360 - (-alpha) % Wolf.ANG_360; + } + return alpha; + } + + + /** + * @description Get quadrant. + * @memberOf Wolf.Math + * @param {number} angle Radian angle. + * @returns {number} + */ + function getQuadrant(angle) { + angle = Wolf.Angle.normalize(angle); + + if (angle < Math.PI / 2) { + return q_first; + } else if (angle < Math.PI) { + return q_second; + } else if (angle < 3 * Math.PI / 2) { + return q_third; + } else { + return q_fourth; + } + } + + /** + * @description Get 4 point direction. + * @memberOf Wolf.Math + * @param {number} angle Radian angle. + * @returns {number} Directional point. + */ + function get4dir(angle) { + angle = Wolf.Angle.normalize(angle + Math.PI / 4); + + if (angle < Math.PI / 2) { + return dir4_east; + } else if( angle < Math.PI ) { + return dir4_north; + } else if( angle < 3 * Math.PI / 2 ) { + return dir4_west; + } else { + return dir4_south; + } + } + + /** + * @description Get 8 point direction. + * @memberOf Wolf.Math + * @param {number} angle Radian angle. + * @returns {number} Directional point. + */ + function get8dir(angle) { + angle = Wolf.Angle.normalize(angle + Math.PI / 12); + + if ( angle <= (Math.PI / 4)) { + return dir8_east; + } else if (angle < (Math.PI / 2)) { + return dir8_northeast; + } else if (angle <= (3 * Math.PI / 4)) { + return dir8_north; + } else if (angle < Math.PI) { + return dir8_northwest; + } else if (angle <= (5 * Math.PI / 4)) { + return dir8_west; + } else if (angle < (3 * Math.PI / 2)) { + return dir8_southwest; + } else if (angle <= (7 * Math.PI / 4)) { + return dir8_south; + } else { + return dir8_southeast; + } + } + + /** + * @description calculates distance between a point (x, y) and a line. + * @memberOf Wolf.Math + * @param {number} x X coord of point + * @param {number} y Y coord of point + * @param {number} a Line angle in degrees + * @returns {number} Distance + */ + function point2LineDist(x, y, a) { + return Math.abs( (x * SinTable[a] - y * CosTable[a]) >> 0); + } + + + + /** + * @description Calculates line length to the point nearest to (poin). + * @memberOf Wolf.Math + * @param {number} x X coord of point + * @param {number} y Y coord of point + * @param {number} a Line angle in degrees + * @returns {number} Distance + */ + function lineLen2Point( x, y, a) { + return (x * CosTable[a] + y * SinTable[a]) >> 0; + } + + + /* + point2 = {x,y} + / | + / | + / | + /a______|----------> x + point1 = {x, y} + */ + /** + * @description Returns angle in radians + * @memberOf Wolf.Math + * @param {number} x X coord of point + * @param {number} y Y coord of point + * @param {number} a Line angle in degrees + * @returns {number} Distance + */ + function transformPoint(point1X, point1Y, point2X, point2Y) { + var angle = Math.atan2(point1Y - point2Y, point1X - point2X); + return Wolf.Angle.normalize(angle); + } + + + buildTables(); + + return { + calcFov : calcFov, + normalizeAngle : normalizeAngle, + getQuadrant : getQuadrant, + get4dir : get4dir, + get8dir : get8dir, + point2LineDist : point2LineDist, + lineLen2Point : lineLen2Point, + transformPoint : transformPoint, + + SinTable : SinTable, + CosTable : CosTable, + TanTable : TanTable, + XnextTable : XnextTable, + YnextTable : YnextTable, + ColumnAngle : ColumnAngle, + + dir4_east : dir4_east, + dir4_north : dir4_north, + dir4_west : dir4_west, + dir4_south : dir4_south, + dir4_nodir : dir4_nodir, + dir8_east : dir8_east, + dir8_northeast : dir8_northeast, + dir8_north : dir8_north, + dir8_northwest : dir8_northwest, + dir8_west : dir8_west, + dir8_southwest : dir8_southwest, + dir8_south : dir8_south, + dir8_southeast : dir8_southeast, + dir8_nodir : dir8_nodir, + dx4dir : dx4dir, + dy4dir : dy4dir, + dx8dir : dx8dir, + dy8dir : dy8dir, + dir4angle : dir4angle, + dir8angle : dir8angle, + dir4to8 : dir4to8, + opposite4 : opposite4, + opposite8 : opposite8, + diagonal : diagonal + }; + +})(); \ No newline at end of file diff --git a/js/menu.js b/js/menu.js new file mode 100644 index 0000000..ffb4459 --- /dev/null +++ b/js/menu.js @@ -0,0 +1,622 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Game menu management + */ +Wolf.Menu = (function() { + var setupDone = false, + menuInputActive = false, + activeIndex = 0, + activeMouseItem = null, + activeEpisode, + messageBlink, + activeMessage, + activeSkill; + + var keySprites = {}, + i, + keySpriteNames = [ + "BLANK", + "QUESTION", + "SHIFT", + "SPACE", + "CTRL", + "LEFT", + "RIGHT", + "UP", + "DOWN", + "ENTER", + "DEL", + "PGUP", + "PGDN", + "INS", + "SLASH", + "HOME", + "COMMA", + "PERIOD", + "PLUS", + "MINUS", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z" + ]; + + for (i=0;i. +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Player management + */ +Wolf.Player = (function() { + + Wolf.setConsts({ + PLAYERSIZE : Wolf.MINDIST, // player radius + STOPSPEED : 0x0D00, + FRICTION : 0.25, + MAXMOVE : (Wolf.MINDIST*2-1), + EXTRAPOINTS : 40000, // points for an extra life + ITEM_KEY_1 : 1, + ITEM_KEY_2 : 2, + ITEM_KEY_3 : 4, + ITEM_KEY_4 : 8, + ITEM_WEAPON_1 : 16, + ITEM_WEAPON_2 : 32, + ITEM_WEAPON_3 : 64, + ITEM_WEAPON_4 : 128, + ITEM_WEAPON_5 : 256, + ITEM_WEAPON_6 : 512, + ITEM_WEAPON_7 : 1024, + ITEM_WEAPON_8 : 2048, + ITEM_BACKPACK : (1<<12), // doubles carrying capacity + ITEM_AUGMENT : (1<<13), // adds 50 to maximum health + ITEM_UNIFORM : (1<<14), // allows you to pass guards + ITEM_AUTOMAP : (1<<15), // shows unknown map ares in other color (as in DooM) + ITEM_FREE : (1<<16), // - unused - + PL_FLAG_REUSE : 1, // use button pressed + PL_FLAG_ATTCK : 2, // attacking + // debug (cheat codes) flags + FL_GODMODE : (1<<4), + FL_NOTARGET : (1<<6), + + WEAPON_KNIFE : 0, + WEAPON_PISTOL : 1, + WEAPON_AUTO : 2, + WEAPON_CHAIN : 3, + WEAPON_TYPES : 4, + + KEY_GOLD : 0, + KEY_SILVER : 1, + KEY_FREE1 : 2, + KEY_FREE2 : 3, + KEY_TYPES : 4, + + AMMO_BULLETS : 0, + AMMO_TYPES : 1, + + ex_notingame : 0, + ex_playing : 1, + ex_dead : 2, + ex_secretlevel : 3, + ex_victory : 4, + ex_complete : 5, + + // victory animation + BJRUNSPEED : 2048, + BJJUMPSPEED : 680 + + }); + + + + /* + struct atkinf + { + char tics, attack, frame; // attack is 1 for gun, 2 for knife + } + */ + var attackinfo = [ // 4 guns, 14 frames max for every gun! + [ {tics:6,attack:0,frame:1},{tics:6,attack:2,frame:2},{tics:6,attack:0,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ], + [ {tics:6,attack:0,frame:1},{tics:6,attack:1,frame:2},{tics:6,attack:0,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ], + [ {tics:6,attack:0,frame:1},{tics:6,attack:1,frame:2},{tics:6,attack:3,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ], + [ {tics:6,attack:0,frame:1},{tics:6,attack:1,frame:2},{tics:6,attack:4,frame:3},{tics:6,attack:-1,frame:0}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ] + ]; + + + /** + * @description Spawn the player + * @memberOf Wolf.Player + * @param {object} location The location to spawn the player {origin, angle} + * @param {object} level The level object + * @param {number} skill The difficulty level + * @param {object} [oldPlayer] A player object to copy score and weapons from + * @returns {object} The new player object + */ + function spawn(location, level, skill, oldPlayer) { + + var x = location.x, + y = location.y, + angle = location.angle, + tileX = Wolf.POS2TILE(x), + tileY = Wolf.POS2TILE(y), + areanumber = level.areas[tileX][tileY]; + + // Player structure: Holds all info about player + var player = { + episode : -1, + level : -1, + health : 100, + frags : 0, + ammo : [ + ], + score : 0, + lives : 0, + startScore : 0, + nextExtra : 0, + items : 0, // (keys, weapon) + weapon : 0, + pendingWeapon : -1, + previousWeapon : -1, + position : { + x : x, + y : y + }, + angle : angle, + tile : { + x : tileX, + y : tileY + }, + mov : { + x : 0, + y : 0 + }, + speed : 0, + armor : 0, // there are 2 types. The better one is indicated by high bit set + cmd : { // movement / action command + forwardMove : 0, + sideMove : 0, + buttons : 0, + impulse : 0 + }, + attackFrame : 0, // attack info + attackCount : 0, + weaponFrame : 0, + + madenoise : false, + lastAttacker : null, + + faceFrame : 0, + faceCount : 0, // bj's face in the HUD // FIXME decide something! + faceGotGun : false, + faceOuch : false, + + flags : 0, + areanumber : areanumber, + playstate : 0, + + attackDirection : [0,0], + + skill : skill + }; + + if (player.areanumber < 0) { + player.areanumber = 36; + } + + Wolf.Areas.init(level, player.areanumber); + Wolf.Areas.connect(level, player.areanumber); + + if (oldPlayer) { + copyPlayer(player, oldPlayer); + } else { + newGame(player); + } + + return player; + } + + + /** + * @description Copy player variables from another player object + * @private + * @param {object} player The player object + * @param {object} copyPlayer The player object to copy from + */ + function copyPlayer(player, copyPlayer) { + player.health = copyPlayer.health; + player.ammo = copyPlayer.ammo; + player.score = copyPlayer.score; + player.startScore = copyPlayer.startScore; + player.lives = copyPlayer.lives; + player.previousWeapon = copyPlayer.previousWeapon; + player.weapon = copyPlayer.weapon; + player.pendingWeapon = copyPlayer.pendingWeapon; + player.items = (copyPlayer.items & Wolf.ITEM_WEAPON_1) | + (copyPlayer.items & Wolf.ITEM_WEAPON_2) | + (copyPlayer.items & Wolf.ITEM_WEAPON_3) | + (copyPlayer.items & Wolf.ITEM_WEAPON_4); + player.nextExtra = copyPlayer.nextExtra; + } + + /** + * @description Set up player for the new game + * @memberOf Wolf.Player + * @param {object} player The player object + */ + function newGame(player) { + player.health = 100; + player.ammo[Wolf.AMMO_BULLETS] = 8; + player.score = 0; + player.startScore = 0; + player.lives = 3; + player.previousWeapon = Wolf.WEAPON_KNIFE; //gsh + player.weapon = player.pendingWeapon = Wolf.WEAPON_PISTOL; + player.items = Wolf.ITEM_WEAPON_1 | Wolf.ITEM_WEAPON_2; + player.nextExtra = Wolf.EXTRAPOINTS; + } + + + + /** + * @description Try to move player + * @private + * @param {object} player The player object. + * @param {object} level The level object. + * @returns {boolean} Returns true if move was ok + */ + function tryMove(player, level) { + var xl, yl, xh, yh, x, y, + d, n; + + xl = Wolf.POS2TILE(player.position.x - Wolf.PLAYERSIZE ); + yl = Wolf.POS2TILE(player.position.y - Wolf.PLAYERSIZE ); + xh = Wolf.POS2TILE(player.position.x + Wolf.PLAYERSIZE ); + yh = Wolf.POS2TILE(player.position.y + Wolf.PLAYERSIZE ); + + // Cheching for solid walls: + for (y = yl; y <= yh; ++y) { + for (x = xl; x <= xh; ++x) { + if (level.tileMap[x][y] & Wolf.SOLID_TILE) { + return false; + } + if (level.tileMap[x][y] & Wolf.DOOR_TILE && Wolf.Doors.opened(level.state.doorMap[x][y]) != Wolf.DOOR_FULLOPEN) { + // iphone hack to allow player to move halfway into door tiles + // if the player bounds doesn't cross the middle of the tile, let the move continue + if (Math.abs(player.position.x - Wolf.TILE2POS(x)) <= 0x9000 && Math.abs(player.position.y - Wolf.TILE2POS(y)) <= 0x9000) { + return false; + } + } + } + } + + // check for actors + for (n = 0; n < level.state.numGuards; ++n) { + if (level.state.guards[n].state >= Wolf.st_die1) { + continue; + } + if (!(level.state.guards[n].flags & Wolf.FL_SHOOTABLE)) { + continue; + } + + d = player.position.x - level.state.guards[n].x; + if (d < -Wolf.MINACTORDIST || d > Wolf.MINACTORDIST) { + continue; + } + + d = player.position.y - level.state.guards[n].y; + if (d < -Wolf.MINACTORDIST || d > Wolf.MINACTORDIST) { + continue; + } + return false; + } + + return true; + } + + /** + * @description Clips movement + * @private + * @param {object} self The player object. + * @param {number} xmove Movement in x direction + * @param {number} ymove Movement in y direction + * @param {object} level The level object. + */ + function clipMove(self, xmove, ymove, level) { + var basex, basey; + + basex = self.position.x; + basey = self.position.y; + + self.position.x += xmove; + self.position.y += ymove; + if (tryMove(self, level)) { + return; // we moved as we wanted + } + + if (xmove) { // don't bother if we don't move x! + self.position.x = basex + xmove; + self.position.y = basey; + if (tryMove(self, level)) { + return; // May be we'll move only X direction? + } + } + if (ymove) { // don't bother if we don't move y! + self.position.x = basex; + self.position.y = basey + ymove; + if (tryMove(self, level)) { + return; // May be we'll move only Y direction? + } + } + + // movement blocked; we must stay on one place... :( + self.position.x = basex; + self.position.y = basey; + } + + + /** + * @description Changes player's angle and position + * @memberOf Wolf.Player + * @param {object} game The game object. + * @param {object} self The player object. + * @param {object} level The level object. + * @param {object} tics Number of tics. + */ + function controlMovement(game, self, level, tics) { + var angle, speed; + + // rotation + angle = self.angle; + + self.mov.x = self.mov.y = 0; // clear accumulated movement + + if (self.cmd.forwardMove ) { + speed = tics * self.cmd.forwardMove; + self.mov.x += (speed * Wolf.Math.CosTable[angle])>>0; + self.mov.y += (speed * Wolf.Math.SinTable[angle])>>0; + } + if (self.cmd.sideMove) { + speed = tics * self.cmd.sideMove; + self.mov.x += (speed * Wolf.Math.SinTable[angle])>>0; + self.mov.y -= (speed * Wolf.Math.CosTable[angle])>>0; + } + + if (!self.mov.x && !self.mov.y) { + return; + } + + self.speed = self.mov.x + self.mov.y; + + // bound movement + if (self.mov.x > Wolf.MAXMOVE) { + self.mov.x = Wolf.MAXMOVE; + } else if (self.mov.x < -Wolf.MAXMOVE) { + self.mov.x = -Wolf.MAXMOVE; + } + + if (self.mov.y > Wolf.MAXMOVE) { + self.mov.y = Wolf.MAXMOVE; + } else if (self.mov.y < -Wolf.MAXMOVE) { + self.mov.y = -Wolf.MAXMOVE; + } + + // move player and clip movement to walls (check for no-clip mode here) + clipMove(self, self.mov.x, self.mov.y, level); + self.tile.x = Wolf.POS2TILE(self.position.x); + self.tile.y = Wolf.POS2TILE(self.position.y); + + // Powerup_PickUp( self.tilex, self.tiley ); + + // pick up items easier -- any tile you touch, instead of + // just the midpoint tile + var x, y, tileX, tileY; + for (x = -1 ;x <= 1; x+= 2) { + tilex = Wolf.POS2TILE(self.position.x + x * Wolf.PLAYERSIZE); + for (y = -1; y <= 1; y+= 2) { + tiley = Wolf.POS2TILE(self.position.y + y * Wolf.PLAYERSIZE); + Wolf.Powerups.pickUp(level, self, tilex, tiley); + } + } + + // Checking for area change, ambush tiles and doors will have negative values + if (level.areas[self.tile.x][self.tile.y] >= 0 && level.areas[self.tile.x][self.tile.y] != self.areanumber) { + self.areanumber = level.areas[self.tile.x][self.tile.y]; + // assert( self.areanumber >= 0 && self.areanumber < Wolf.NUMAREAS ); + Wolf.Areas.connect(level, self.areanumber); + } + + if (level.tileMap[self.tile.x][self.tile.y] & Wolf.EXIT_TILE) { + //Wolf.Game.startIntermission(0); + Wolf.Game.victory(game); + } + } + + + /** + * @description Called if player pressed USE button + * @private + * @param {object} self The player object. + * @param {object} level The level object. + * @returns {boolean} True if the player used something. + */ + function use(self, game) { + var x, y, dir, newtex, + level = game.level; + + dir = Wolf.Math.get4dir(Wolf.FINE2RAD(self.angle)); + x = self.tile.x + Wolf.Math.dx4dir[dir]; + y = self.tile.y + Wolf.Math.dy4dir[dir]; + + if (level.tileMap[x][y] & Wolf.DOOR_TILE) { + return Wolf.Doors.tryUse(level, self, level.state.doorMap[x][y]); + } + + if (level.tileMap[x][y] & Wolf.SECRET_TILE) { + return Wolf.PushWall.push(level, x, y, dir); + } + + if (level.tileMap[x][y] & Wolf.ELEVATOR_TILE) { + switch (dir) { + case Wolf.Math.dir4_east: + case Wolf.Math.dir4_west: + newtex = level.wallTexX[x][y] += 2; + break; + case Wolf.Math.dir4_north: + case Wolf.Math.dir4_south: + return false; // don't allow to press elevator rails + } + + if (level.tileMap[self.tile.x][self.tile.y] & Wolf.SECRETLEVEL_TILE) { + self.playstate = Wolf.ex_secretlevel; + } else { + self.playstate = Wolf.ex_complete; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_BODY, "lsfx/040.wav", 1, Wolf.ATTN_NORM, 0 ); + + Wolf.Game.startIntermission(game); + + return true; + } + + return false; + } + + /** + * @description Attack + * @memberOf Wolf.Player + * @param {object} game The game object. + * @param {object} player The player object. + * @param {boolean} reAttack True if re-attack + * @param {number} tics The number of tics + */ + function attack(game, player, reAttack, tics) { + var cur, + level = game.level; + + player.attackCount -= tics; + while (player.attackCount <= 0) { + cur = attackinfo[player.weapon][player.attackFrame]; + switch (cur.attack) { + case -1: + player.flags &= ~Wolf.PL_FLAG_ATTCK; + if (!player.ammo[Wolf.AMMO_BULLETS]) { + player.weapon = Wolf.WEAPON_KNIFE; + } else if (player.weapon != player.pendingWeapon) { + player.weapon = player.pendingWeapon; + } + player.attackFrame = player.weaponFrame = 0; + return; + case 4: + if (!player.ammo[Wolf.AMMO_BULLETS]) { + break; + } + if (reAttack) { + player.attackFrame -= 2; + } + case 1: + if (!player.ammo[Wolf.AMMO_BULLETS]) { // can only happen with chain gun + player.attackFrame++; + break; + } + Wolf.Weapon.fireLead(game, player); + player.ammo[Wolf.AMMO_BULLETS]--; + break; + case 2: + Wolf.Weapon.fireHit(game, player); + break; + case 3: + if (player.ammo[Wolf.AMMO_BULLETS] && reAttack) { + player.attackFrame -= 2; + } + break; + } + + player.attackCount += cur.tics; + player.attackFrame++; + player.weaponFrame = attackinfo[player.weapon][player.attackFrame].frame; + } + + } + + /** + * @description Award points to the player + * @memberOf Wolf.Player + * @param {object} player The player object. + * @param {number} points The number of points. + */ + function givePoints(player, points) { + player.score += points; + while (player.score >= player.nextExtra) { + player.nextExtra += Wolf.EXTRAPOINTS; + giveLife(player); + Wolf.log("Extra life!"); + } + } + + /* + ----------------------------------------------------------------------------- + Returns: returns true if player needs this health. + + Notes: + gives player some HP + max can be: + 0 - natural player's health limit (100 or 150 with augment) + >0 - indicates the limit + ----------------------------------------------------------------------------- + */ + function giveHealth(player, points, max) { + if (max == 0) { + max = (player.items & Wolf.ITEM_AUGMENT) ? 150 : 100; + } + + if (player.health >= max) { + return false; // doesn't need this health + } + + player.health += points; + + if (player.health > max) { + player.health = max; + } + + player.faceGotGun = false; + + return true; // took it + } + + function giveLife(player) { + if (player.lives < 9) { + player.lives++; + } + } + + + function giveKey(player, key) { + player.items |= Wolf.ITEM_KEY_1 << key; + } + + + function giveWeapon(player, weapon) { + var itemflag; + + giveAmmo(player, Wolf.AMMO_BULLETS, 6); // give some ammo with a weapon + + itemflag = Wolf.ITEM_WEAPON_1 << weapon; + if (player.items & itemflag) { + return; // player owns this weapon + } else { + player.items |= itemflag; + + // don't switch if already using better weapon + if (player.weapon < weapon ) { + player.weapon = player.pendingWeapon = weapon; + } + } + } + + + + function giveAmmo(player, type, ammo) { + var maxAmmo = 99; + + if (player.items & Wolf.ITEM_BACKPACK) { + maxAmmo *= 2; + } + + if (player.ammo[type] >= maxAmmo) { + return false; // don't need + } + + if (!player.ammo[type] && !player.attackFrame) { + // knife was out + player.weapon = player.pendingWeapon; + } + + player.ammo[type] += ammo; + if (player.ammo[type] > maxAmmo) { + player.ammo[type] = maxAmmo; + } + + return true; + } + + + /** + * @description Award points to the player + * @memberOf Wolf.Player + * @param {object} player The player object. + * @param {object} attacker The attacker actor object. + * @param {number} points The number of damage points. + * @param {number} skill The difficulty level. + */ + function damage(player, attacker, points, skill) { + var dx, dy, + angle, playerAngle, deltaAngle; + + if (player.playstate == Wolf.ex_dead || player.playstate == Wolf.ex_complete || self.playstate == Wolf.ex_victory) { + return; + } + + player.lastAttacker = attacker; + + if (skill == Wolf.gd_baby) { + points >>= 2; + } + + // note the direction of the last hit for the directional blends + dx = attacker.x - player.position.x; + dy = attacker.y - player.position.y; + + // probably won't ever have damage from self, but check anyway + if (dx != 0 || dy != 0) { + angle = Math.atan2(dy, dx); + playerAngle = player.angle * 360.0 / Wolf.ANG_360; + + angle = angle * 180.0 / Math.PI; + + if (angle < 0) { + angle = 360 + angle; + } + + deltaAngle = angle - playerAngle; + + if (deltaAngle > 180) { + deltaAngle = deltaAngle - 360; + } + if (deltaAngle < -180) { + deltaAngle = 360 + deltaAngle; + } + if (deltaAngle > 40) { + player.attackDirection[0] = 1; + } else if (deltaAngle < -40) { + player.attackDirection[1] = 1; + } + } + // do everything else but subtract health in god mode, to ease + // testing of damage feedback + if (!(player.flags & Wolf.FL_GODMODE) ) { + player.health -= points; + } + + if (player.health <= 0) { + // dead + Wolf.Game.notify("You have died"); + player.health = 0; + player.playstate = Wolf.ex_dead; + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_BODY, "lsfx/009.wav", 1, Wolf.ATTN_NORM, 0); + } + + // red screen flash + Wolf.Game.startDamageFlash(points); + + // stop the happy grin face if shot before it times out + player.faceGotGun = false; + + // make BJ's eyes bulge on huge hits + if (points > 30 && player.health != 0) { + player.faceOuch = true; + player.faceCount = 0; + } + } + + function victorySpin(game, player, tics) { + var desty; + + if (player.angle > Wolf.ANG_270) { + player.angle -= tics * Wolf.ANG_1 * 3; + if (player.angle < Wolf.ANG_270) { + player.angle = Wolf.ANG_270; + } + } else if (player.angle < Wolf.ANG_270) { + player.angle += tics * Wolf.ANG_1 * 3; + if (player.angle > Wolf.ANG_270) { + player.angle = Wolf.ANG_270; + } + } + + //desty = ((player.tile.y-5) << Wolf.TILESHIFT) - 0x3000; + desty = Wolf.TILE2POS(player.tile.y+7) + + if (player.position.y < desty) { + player.position.y += tics * 3072; + if (player.position.y > desty) { + player.position.y = desty; + } + } + } + + /** + * @description Process player actions + * @memberOf Wolf.Player + * @param {object} self The player object. + * @param {object} game The game object. + * @param {number} tics Tics since last processing. + */ + function process(game, self, tics) { + var level = game.level, + n; + + + if (self.playstate == Wolf.ex_victory) { + victorySpin(game, self, tics); + return; + } + + self.attackDirection = [0,0]; + self.madenoise = false; + + controlMovement(game, self, level, tics); + + if (self.flags & Wolf.PL_FLAG_ATTCK) { + attack(game, self, self.cmd.buttons & Wolf.BUTTON_ATTACK, tics); + } else { + if (self.cmd.buttons & Wolf.BUTTON_USE) { + if (!(self.flags & Wolf.PL_FLAG_REUSE) && use(self, game)) { + self.flags |= Wolf.PL_FLAG_REUSE; + } + } else { + self.flags &= ~Wolf.PL_FLAG_REUSE; + } + if (self.cmd.buttons & Wolf.BUTTON_ATTACK) { + self.flags |= Wolf.PL_FLAG_ATTCK; + + self.attackFrame = 0; + self.attackCount = attackinfo[self.weapon][0].tics; + self.weaponFrame = attackinfo[self.weapon][0].frame; + } + } + + // process impulses + switch (self.cmd.impulse) { + case 0: + break; // no impulse + + case 1: + case 2: + case 3: + case 4: + changeWeapon(self, self.cmd.impulse - 1); + break; + + case 10: // next weapon /like in Quake/ FIXME: weapprev, weapnext + self.pendingWeapon = self.weapon; + for (n = 0; n < 4; ++n) { + if (++self.weapon > Wolf.WEAPON_CHAIN) { + self.weapon = Wolf.WEAPON_KNIFE; + } + if (changeWeapon(self, self.weapon)) { + break; + } + } + self.weapon = self.pendingWeapon; + break; + + default: + Wolf.log("Unknown Impulse: ", + self.cmd.impulse); + break; + } + } + + return { + spawn : spawn, + newGame : newGame, + controlMovement : controlMovement, + process : process, + damage : damage, + givePoints : givePoints, + giveHealth : giveHealth, + giveAmmo : giveAmmo, + giveWeapon : giveWeapon, + giveLife : giveLife, + giveKey : giveKey + }; + +})(); diff --git a/js/powerups.js b/js/powerups.js new file mode 100644 index 0000000..4365af7 --- /dev/null +++ b/js/powerups.js @@ -0,0 +1,309 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +Wolf.Powerups = (function() { + + Wolf.setConsts({ + pow_gibs : 0, // 1% if <=10%; SLURPIESND + pow_gibs2 : 1, // 1% if <=10%; SLURPIESND + pow_alpo : 2, // 4% if <100%; HEALTH1SND + pow_firstaid : 3, // 25% if <100%; HEALTH2SND + pow_key1 : 4, // gold key; GETKEYSND + pow_key2 : 5, // silver key; GETKEYSND + pow_key3 : 6, // not used + pow_key4 : 7, // not used + pow_cross : 8, // 100pts; BONUS1SND + pow_chalice : 9, // 500pts; BONUS2SND + pow_bible : 10, // 1000pts; BONUS3SND + pow_crown : 11, // 5000pts; BONUS4SND + pow_clip : 12, // 8bul if <99bul; GETAMMOSND + pow_clip2 : 13, // 4bul if <99bul; GETAMMOSND + pow_machinegun : 14, // machine gun; GETMACHINESND + pow_chaingun : 15, // gatling gun; GETGATLINGSND + pow_food : 16, // 10% if <100%; HEALTH1SND + pow_fullheal : 17, // 99%, 25bul; BONUS1UPSND + pow_25clip : 18, // 25bul if <99bul; GETAMMOBOXSND + pow_spear : 19, // spear of destiny! + pow_last : 20 + // add new types here (after last) + }); + + var texture = [ + Wolf.SPR_STAT_34, // pow_gibs + Wolf.SPR_STAT_38, // pow_gibs2 + Wolf.SPR_STAT_6, // pow_alpo + Wolf.SPR_STAT_25, // pow_firstaid + Wolf.SPR_STAT_20, // pow_key1 + Wolf.SPR_STAT_21, // pow_key2 + // not used + Wolf.SPR_STAT_20, // pow_key3 + Wolf.SPR_STAT_20, // pow_key4 + + Wolf.SPR_STAT_29, // pow_cross + Wolf.SPR_STAT_30, // pow_chalice + Wolf.SPR_STAT_31, // pow_bible + Wolf.SPR_STAT_32, // pow_crown + Wolf.SPR_STAT_26, // pow_clip + Wolf.SPR_STAT_26, // pow_clip2 + Wolf.SPR_STAT_27, // pow_machinegun + Wolf.SPR_STAT_28, // pow_chaingun + Wolf.SPR_STAT_24, // pow_food + Wolf.SPR_STAT_33, // pow_fullheal + // spear + Wolf.SPR_STAT_49, // pow_25clip + Wolf.SPR_STAT_51 // pow_spear + ]; + + + function remove(level, powerup) { + powerup.x = -1; + powerup.y = -1; + } + + function addNew(level) { + /* + for (var i = 0;i < level.state.numPowerups; i++ ) { + if (level.state.powerups[i].x == -1 ) { + return level.state.powerups[i]; + } + } + */ + /* + if (level.state.numPowerups == Wolf.MAX_POWERUPS ) { + return level.state.powerups[0]; + } + */ + level.state.numPowerups++; + + var newp = { + x : -1, + y : -1, + type : 0, + sprite : null + }; + + level.state.powerups[level.state.numPowerups-1] = newp; + + return newp; + } + + function reset(level) { + level.state.numPowerups = 0; + level.state.powerups = []; + } + + // x,y are in TILES. + function spawn(level, x, y, type) { + var newp = addNew(level); + + newp.sprite = Wolf.Sprites.getNewSprite(level); + newp.type = type; + + Wolf.Sprites.setPos(level, newp.sprite, Wolf.TILE2POS(newp.x = x), Wolf.TILE2POS(newp.y = y), 0); + + Wolf.Sprites.setTex(level, newp.sprite, -1, texture[type]); + + level.tileMap[x][y] |= Wolf.POWERUP_TILE; + // good place to update total treasure count! + } + + + function give(level, player, type) { + var keynames = ["Gold", "Silver", "?", "?"]; + + switch (type) { + // Keys + case Wolf.pow_key1: + case Wolf.pow_key2: + case Wolf.pow_key3: + case Wolf.pow_key4: + type -= Wolf.pow_key1; + Wolf.Player.giveKey(player, type); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/012.wav", 1, Wolf.ATTN_NORM, 0); + Wolf.Game.notify(keynames[type] + " key"); + break; + // Treasure + case Wolf.pow_cross: + Wolf.Player.givePoints(player, 100); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/035.wav", 1, Wolf.ATTN_NORM, 0); + if ( ++level.state.foundTreasure == level.state.totalTreasure ) { + Wolf.Game.notify("You found the last treasure!"); + } + break; + + case Wolf.pow_chalice: + Wolf.Player.givePoints(player, 500); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/036.wav", 1, Wolf.ATTN_NORM, 0); + if (++level.state.foundTreasure == level.state.totalTreasure) { + Wolf.Game.notify("You found the last treasure!"); + } + break; + + case Wolf.pow_bible: + Wolf.Player.givePoints(player, 1000); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/037.wav", 1, Wolf.ATTN_NORM, 0); + if (++level.state.foundTreasure == level.state.totalTreasure) { + Wolf.Game.notify("You found the last treasure!"); + } + break; + + case Wolf.pow_crown: + Wolf.Player.givePoints(player, 5000); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/045.wav", 1, Wolf.ATTN_NORM, 0); + if (++level.state.foundTreasure == level.state.totalTreasure) { + Wolf.Game.notify("You found the last treasure!"); + } + break; + + // Health + case Wolf.pow_gibs: + if (!Wolf.Player.giveHealth(player, 1, 11)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/061.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.pow_alpo: + if (!Wolf.Player.giveHealth(player, 4, 0)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/033.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.pow_food: + if (!Wolf.Player.giveHealth(player, 10, 0)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/033.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.pow_firstaid: + if (!Wolf.Player.giveHealth(player, 25, 0)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/034.wav", 1, Wolf.ATTN_NORM, 0); + break; + + // Weapon & Ammo + case Wolf.pow_clip: + if (!Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 8)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/031.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.pow_clip2: + if (!Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 4)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/031.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.pow_25clip: + if (!Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 25)) { + return false; + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/031.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.pow_machinegun: + Wolf.Player.giveWeapon(player, Wolf.WEAPON_AUTO ); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/030.wav", 1, Wolf.ATTN_NORM, 0); + Wolf.Game.notify("Machinegun"); + break; + + case Wolf.pow_chaingun: + Wolf.Player.giveWeapon(player, Wolf.WEAPON_CHAIN ); + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/038.wav", 1, Wolf.ATTN_NORM, 0); + Wolf.Game.notify("Chaingun"); + + player.faceCount = -100; + player.faceGotGun = true; + break; + + // Artifacts + case Wolf.pow_fullheal: + // go to 150 health + Wolf.Player.giveHealth(player, 99, 99 ); + Wolf.Player.giveAmmo(player, Wolf.AMMO_BULLETS, 25 ); + Wolf.Player.giveLife(player); + if (++level.state.foundTreasure == level.state.totalTreasure) { + Wolf.Game.notify("You found the last treasure!"); + } else { + Wolf.Game.notify("Full Heal"); + } + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_ITEM, "lsfx/034.wav", 1, Wolf.ATTN_NORM, 0); + Wolf.log("Extra life!"); + break; + + default: + Wolf.log("Warning: Unknown item type: " + type); + break; + } + + Wolf.Game.startBonusFlash(); + + return true; + } + + // x,y are in TILES. + function pickUp(level, player, x, y) { + var i, pow, + p_left = false, + p_pick = false; + + for (i=0; i. +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Push wall management + */ +Wolf.PushWall = (function() { + + var PWall = {}; + reset(); + + function reset() { + PWall.active = false; + PWall.tilesMoved = 0; + PWall.pointsMoved = 0; + PWall.dir = 0; + PWall.x = 0; + PWall.y = 0; + PWall.dx = 0; + PWall.dy = 0; + PWall.texX = 0; + PWall.texY = 0; + } + + + function push(level, x, y, dir) { + var dx, dy; + + if (PWall.active) { + return false; // another PWall is moving [only one at a time!] + } + + dx = Wolf.Math.dx4dir[dir]; + dy = Wolf.Math.dy4dir[dir]; + + if (level.tileMap[x + dx][y + dy] & (Wolf.SOLID_TILE | Wolf.DOOR_TILE)) { + // noway (smth is blocking) + return true; + } + + // remove secret flag & make everything needed when pushwall used! + level.tileMap[x][y] &= (~Wolf.SECRET_TILE); + level.tileMap[x][y] &= (~Wolf.WALL_TILE); + level.tileMap[x][y] |= Wolf.PUSHWALL_TILE; + + if (++level.state.foundSecrets == level.state.totalSecrets) { + Wolf.Game.notify("You found the last secret!"); + } else { + Wolf.Game.notify("You found a secret!"); + } + + Wolf.Sound.startSound(null, null, 1, Wolf.CHAN_AUTO, "sfx/034.wav", 1, Wolf.ATTN_STATIC, 0); + + // good way to avoid stuckness; [un]comment one more down! + // it makes a tile behind pushwall unpassable + level.tileMap[x + dx][y + dy] |= Wolf.PUSHWALL_TILE; + level.wallTexX[x + dx][y + dy] = level.wallTexX[x][y]; + level.wallTexY[x + dx][y + dy] = level.wallTexY[x][y]; + + // write down PWall info + PWall.active = true; + PWall.tilesMoved = PWall.pointsMoved = 0; + PWall.dir = dir; + PWall.x = x; + PWall.y = y; + PWall.dx = dx; + PWall.dy = dy; + PWall.texX = level.wallTexX[x][y]; + PWall.texY = level.wallTexY[x][y]; + + return true; + } + + + function process(level, tics) { + if (!PWall.active) { + return; // no active PWall to work with + } + + PWall.pointsMoved += tics; + + if (PWall.pointsMoved < 128) { + return; + } + + PWall.pointsMoved -= 128; + PWall.tilesMoved++; + // Free tile + level.tileMap[PWall.x][PWall.y] &= (~Wolf.PUSHWALL_TILE); + // Occupy new tile + PWall.x += PWall.dx; + PWall.y += PWall.dy; + + // Shall we move further? + 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) { + level.tileMap[PWall.x][PWall.y] &= (~Wolf.PUSHWALL_TILE); // wall now + level.tileMap[PWall.x][PWall.y] |= Wolf.WALL_TILE; // wall now + level.wallTexX[PWall.x][PWall.y] = PWall.texX; + level.wallTexY[PWall.x][PWall.y] = PWall.texY; + PWall.active = false; // Free Push Wall + } else { + level.tileMap[PWall.x + PWall.dx][PWall.y + PWall.dy] |= Wolf.PUSHWALL_TILE; + + // Not sure if this is right but it fixed an issue with the pushwall texture changing mid-slide. + level.wallTexX[PWall.x + PWall.dx][PWall.y + PWall.dy] = PWall.texX; + level.wallTexY[PWall.x + PWall.dx][PWall.y + PWall.dy] = PWall.texY; + } + } + + function get() { + return PWall; + } + + return { + reset : reset, + process : process, + push : push, + get : get + }; + +})(); diff --git a/js/random.js b/js/random.js new file mode 100644 index 0000000..a1ff58d --- /dev/null +++ b/js/random.js @@ -0,0 +1,74 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +Wolf.Random = (function() { + +/* This is just John Carmack's table driven pseudo-random number generator */ +var rndtable = [ + 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, + 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, + 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, + 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, + 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242, + 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0, + 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235, + 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113, + 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75, + 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196, + 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113, + 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241, + 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224, + 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95, + 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226, + 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, + 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, + 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136, + 120, 163, 236, 249 +]; + +var rndindex = 0; + +function init(randomize) { + if (randomize ) { + rndindex = (new Date).getTime() & 0xFF; + } else { + rndindex = 0; + } +} + +function rnd() { + rndindex++; + rndindex &= 0xFF; + return rndtable[rndindex]; +} + + +return { + init : init, + rnd : rnd +} + +})(); \ No newline at end of file diff --git a/js/raycaster.js b/js/raycaster.js new file mode 100644 index 0000000..923264b --- /dev/null +++ b/js/raycaster.js @@ -0,0 +1,302 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +Wolf.setConsts({ + UPPERZCOORD : 0.6, + LOWERZCOORD : -0.6, + + // marks + TRACE_MARK_MAP : 1, // marks traced area in 'AM_AutoMap.vis' array + // obstacle levels + TRACE_SIGHT : 2, // player sight + TRACE_SIGHT_AI : 4, // enemy sight + TRACE_BULLET : 8, // bullet + TRACE_OBJECT : 16, // object + + TRACE_HIT_VERT : 32, // vertical wall was hit + TRACE_HIT_DOOR : 64, // door was hit + TRACE_HIT_PWALL : 128 // pushwall was hit +}); + +Wolf.Raycaster = (function() { + + var x_tile_step = [ 1, -1, -1, 1 ], + y_tile_step = [ 1, 1, -1, -1 ]; + + var TILESHIFT = Wolf.TILESHIFT, + TRACE_HIT_VERT = Wolf.TRACE_HIT_VERT, + TILEGLOBAL = Wolf.TILEGLOBAL, + WALL_TILE = Wolf.WALL_TILE, + DOOR_TILE = Wolf.DOOR_TILE, + TILE2POS = Wolf.TILE2POS, + POS2TILE = Wolf.POS2TILE, + FINE2RAD = Wolf.FINE2RAD, + TRACE_HIT_DOOR = Wolf.TRACE_HIT_DOOR, + PUSHWALL_TILE = Wolf.PUSHWALL_TILE, + TRACE_HIT_PWALL = Wolf.TRACE_HIT_PWALL, + DOOR_FULLOPEN = Wolf.DOOR_FULLOPEN, + XnextTable = Wolf.Math.XnextTable, + YnextTable = Wolf.Math.YnextTable, + getQuadrant = Wolf.Math.getQuadrant, + TanTable = Wolf.Math.TanTable; + + function traceCheck(tileMap, doorMap, visibleTiles, x, y, frac, dfrac, vert, flip, tracePoint) { + var door; + + if (tileMap[x][y] & WALL_TILE) { + if (vert) { + tracePoint.x = (x << TILESHIFT) + (flip ? TILEGLOBAL : 0); + tracePoint.y = (y << TILESHIFT) + frac; + tracePoint.flags |= TRACE_HIT_VERT; + } else { + tracePoint.x = (x << TILESHIFT) + frac; + tracePoint.y = (y << TILESHIFT) + (flip ? TILEGLOBAL : 0); + tracePoint.flags &= ~TRACE_HIT_VERT; + } + tracePoint.tileX = x; + tracePoint.tileY = y; + tracePoint.frac = frac / TILEGLOBAL; + + return true; // wall, stop tracing + } + + if (visibleTiles) { + visibleTiles[x][y] = true; // this tile is visible + } + + if (tileMap[x][y] & DOOR_TILE && doorMap[x][y].action != Wolf.dr_open) { + door = doorMap[x][y]; + + frac += dfrac >> 1; + + if (POS2TILE(frac)) { + return false; + } + + if (vert) { + if (door.action != Wolf.dr_closed && (frac >> 10) > DOOR_FULLOPEN - Wolf.Doors.opened(door)) { + return false; // opened enough + } + tracePoint.x = TILE2POS(x); + tracePoint.y = (y << TILESHIFT) + frac; + tracePoint.flags |= TRACE_HIT_VERT; + tracePoint.frac = frac / TILEGLOBAL; + } else { + if (door.action != Wolf.dr_closed && (frac >> 10) < Wolf.Doors.opened(door)) { + return false; // opened enough + } + tracePoint.y = TILE2POS(y); + tracePoint.x = (x << TILESHIFT) + frac; + tracePoint.flags &= ~TRACE_HIT_VERT; + tracePoint.frac = 1 - frac / TILEGLOBAL; + } + + tracePoint.flags |= TRACE_HIT_DOOR; + tracePoint.tileX = x; + tracePoint.tileY = y; + tracePoint.frac += Wolf.Doors.opened(door) / DOOR_FULLOPEN; + return true; // closed door, stop tracing + } + + + if (tileMap[x][y] & PUSHWALL_TILE) { + + var pwall = Wolf.PushWall.get(), + offset = pwall.pointsMoved / 128; + + frac += dfrac * offset; + + if (POS2TILE(frac)) { + return false; + } + + if (vert) { + tracePoint.x = (x << TILESHIFT) + (flip ? TILEGLOBAL : 0) + offset * TILEGLOBAL * (flip ? -1 : 1); + tracePoint.y = (y << TILESHIFT) + frac; + tracePoint.flags |= TRACE_HIT_VERT; + } else { + tracePoint.x = (x << TILESHIFT) + frac; + tracePoint.y = (y << TILESHIFT) + (flip ? TILEGLOBAL : 0) + offset * TILEGLOBAL * (flip ? -1 : 1); + tracePoint.flags &= ~TRACE_HIT_VERT; + } + + tracePoint.flags |= TRACE_HIT_PWALL; + tracePoint.tileX = x; + tracePoint.tileY = y; + tracePoint.frac = frac / TILEGLOBAL; + return true; + } + + return false; // no intersection, go on! + } + + function trace(level, visibleTiles, tracePoint) { + var xtilestep, ytilestep, + xstep, ystep, + xtile, ytile, + xintercept, yintercept, + YmapPos, XmapPos, + tileMap = level.tileMap, + doorMap = level.state.doorMap, + q; + + // Setup for ray casting + q = getQuadrant(FINE2RAD(tracePoint.angle)); + + xtilestep = x_tile_step[q]; + ytilestep = y_tile_step[q]; + + xtile = POS2TILE(tracePoint.x) + xtilestep; + ytile = POS2TILE(tracePoint.y) + ytilestep; + + xstep = ytilestep * XnextTable[tracePoint.angle]; + ystep = xtilestep * YnextTable[tracePoint.angle]; + + xintercept = (((((ytilestep == -1 ? ytile+1 : ytile) << TILESHIFT) - tracePoint.y) + / TanTable[tracePoint.angle])>>0) + tracePoint.x; + yintercept = (((((xtilestep == -1 ? xtile+1 : xtile) << TILESHIFT) - tracePoint.x) + * TanTable[tracePoint.angle])>>0) + tracePoint.y; + + YmapPos = yintercept >> TILESHIFT; // toXray + XmapPos = xintercept >> TILESHIFT; // toYray + + if (visibleTiles) { + // this tile is visible + visibleTiles[POS2TILE(tracePoint.x)][POS2TILE(tracePoint.y)] = true; + } + + var traceCount = 0; + + // Start of ray-casting + while (1) { + + traceCount++; + + // Vertical loop // an analogue for X-Ray + while (!(ytilestep == -1 && YmapPos <= ytile) && !(ytilestep == 1 && YmapPos >= ytile)) { + + if (xtile < 0 || xtile >= 64 || YmapPos < 0 || YmapPos >= 64) { + tracePoint.oob = true; + return; + } + + if (traceCheck(tileMap, doorMap, visibleTiles, xtile, YmapPos, yintercept % TILEGLOBAL, ystep, true, (xtilestep == -1), tracePoint)) { + if (xstep < 0) { + tracePoint.frac = 1 - tracePoint.frac; + } + return; + } + + // prepare for next step + xtile += xtilestep; + yintercept += ystep; + YmapPos = yintercept >> TILESHIFT; + } + + // Horizontal loop // an analogue for Y-Ray + while (!(xtilestep == -1 && XmapPos <= xtile) && !(xtilestep == 1 && XmapPos >= xtile)) { + + if (ytile < 0 || ytile >= 64 || XmapPos < 0 || XmapPos >= 64) { + tracePoint.oob = true; + return; + } + + if (traceCheck(tileMap, doorMap, visibleTiles, XmapPos, ytile, xintercept % TILEGLOBAL, xstep, false, (ytilestep == -1), tracePoint)) { + if (ystep > 0) { + tracePoint.frac = 1 - tracePoint.frac; + } + return; + } + + // prepare for next step + ytile += ytilestep; + xintercept += xstep; + XmapPos = xintercept >> TILESHIFT; + } + + if (traceCount > 1000) { + return; + } + + } // end of while( 1 ) + + + } + + + function traceRays(viewport, level) { + var n, i, j, + tileMap = level.tileMap, + tracePoint, + visibleTiles = [], + numRays = Wolf.XRES / Wolf.SLICE_WIDTH, + tracers = []; + + for (i=0;i<64;i++) { + visibleTiles[i] = []; + for (j=0;j<64;j++) { + visibleTiles[i][j] = 0; + } + } + + // Ray casting + + for (n = 0 ; n < numRays ; ++n) { + + tracePoint = { + x : viewport.x, + y : viewport.y, + angle : Wolf.Math.normalizeAngle(viewport.angle - Wolf.Math.ColumnAngle[n * Wolf.SLICE_WIDTH]), + flags : Wolf.TRACE_SIGHT | Wolf.TRACE_MARK_MAP, + oob : false + }; + + trace(level, visibleTiles, tracePoint); + + tracers[n] = tracePoint; + + // Ugly hack to get rid of "blank slice" glitch due to out-of-bounds raycasting. + // We simply re-use the previous slice if possible. + if (tracePoint.oob) { + if (n > 0 && !tracers[n-1].oob) { + tracers[n] = tracers[n-1]; + } + } + } + + return { + visibleTiles : visibleTiles, + tracers : tracers + }; + } + + + return { + traceRays : traceRays, + trace : trace + }; + +})(); diff --git a/js/renderer.js b/js/renderer.js new file mode 100644 index 0000000..1d433e1 --- /dev/null +++ b/js/renderer.js @@ -0,0 +1,434 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +Wolf.setConsts({ + FOV_RAD : 75 * Math.PI / 180, + ISCHROME : /chrome/.test(navigator.userAgent.toLowerCase()), + ISSAFARI : /safari/.test(navigator.userAgent.toLowerCase()), + ISFIREFOX : /firefox/.test(navigator.userAgent.toLowerCase()), + ISXP : /windows nt 5\./.test(navigator.userAgent.toLowerCase()), + ISWEBKIT : /webkit/.test(navigator.userAgent.toLowerCase()) +}); +Wolf.setConsts({ + VIEW_DIST : (Wolf.XRES / 2) / Math.tan((Wolf.FOV_RAD / 2)), + TEXTURERESOLUTION : Wolf.ISCHROME ? 128 : 64 +}); + + +Wolf.Renderer = (function() { + + var slices = [], + useBackgroundImage = Wolf.ISWEBKIT, + texturePath = "art/walls-shaded/" + Wolf.TEXTURERESOLUTION + "/", + spritePath = "art/sprites/" + Wolf.TEXTURERESOLUTION + "/", + sprites = [], + maxDistZ = 64 * 0x10000, + hasInit = false; + visibleSprites = []; + + var TILESHIFT = Wolf.TILESHIFT, + TILEGLOBAL = Wolf.TILEGLOBAL, + TRACE_HIT_VERT = Wolf.TRACE_HIT_VERT, + TRACE_HIT_DOOR = Wolf.TRACE_HIT_DOOR, + WALL_TILE = Wolf.WALL_TILE, + DOOR_TILE = Wolf.DOOR_TILE, + TEX_PLATE = Wolf.TEX_PLATE, + TILE2POS = Wolf.TILE2POS, + POS2TILE = Wolf.POS2TILE, + VIEW_DIST = Wolf.VIEW_DIST, + SLICE_WIDTH = Wolf.SLICE_WIDTH, + WALL_TEXTURE_WIDTH = Wolf.WALL_TEXTURE_WIDTH, + FINE2RAD = Wolf.FINE2RAD, + XRES = Wolf.XRES, + YRES = Wolf.YRES, + MINDIST = Wolf.MINDIST, + cos = Math.cos, + sin = Math.sin, + tan = Math.tan, + atan2 = Math.atan2, + round = Math.round, + sqrt = Math.sqrt; + + function init() { + var image, slice, x; + if (hasInit) { + return; + } + hasInit = true; + + $("#game .renderer") + .width(Wolf.XRES + "px") + .height(Wolf.YRES + "px"); + + for (x=0; x"); + slice.css({ + position : "absolute", + width : Wolf.SLICE_WIDTH + "px", + height : Wolf.YRES + "px", + left : x + "px", + top : 0, + overflow : "hidden" + }); + slice.appendTo("#game .renderer"); + + image = useBackgroundImage ? $("
") : $(""); + + image.css({ + position : "absolute", + display : "block", + top : 0, + height : 0, + width : Wolf.SLICE_WIDTH * Wolf.WALL_TEXTURE_WIDTH + "px", + backgroundSize : "100% 100%" + }); + + var sliceElement = slice[0]; + sliceElement.texture = image[0]; + sliceElement.appendChild(sliceElement.texture); + slices.push(sliceElement); + } + } + + function reset() { + $("#game .renderer .sprite").remove(); + sprites = []; + visibleSprites = []; + } + + function processTrace(viewport, tracePoint) { + var x = tracePoint.x, + y = tracePoint.y, + vx = viewport.x, + vy = viewport.y, + + dx = viewport.x - tracePoint.x, + dy = viewport.y - tracePoint.y, + dist = Math.sqrt(dx*dx + dy*dy), + frac, + h, w, offset; + + // correct for fisheye + dist = dist * cos(FINE2RAD(tracePoint.angle - viewport.angle)); + + w = WALL_TEXTURE_WIDTH * SLICE_WIDTH; + h = (VIEW_DIST / dist * TILEGLOBAL) >> 0; + + if (tracePoint.flags & TRACE_HIT_DOOR) { + if (tracePoint.flags & TRACE_HIT_VERT) { + if (x < vx) { + frac = tracePoint.frac; + } else { + frac = 1 - tracePoint.frac; + } + } else { + if (y < vy) { + frac = 1 - tracePoint.frac; + } else { + frac = tracePoint.frac; + } + } + } else { + frac = 1 - tracePoint.frac; + } + + offset = frac * w; + if (offset > w - SLICE_WIDTH) { + offset = w - SLICE_WIDTH; + } + offset = round(offset / SLICE_WIDTH) * SLICE_WIDTH; + if (offset < 0) { + offset = 0; + } + + return { + w : w, + h : h, + dist : dist, + vert : tracePoint.flags & TRACE_HIT_VERT, + offset : offset + }; + } + + function clear() { + var n, sprite; + for (n=0;n> 0, + height = proc.h, + z = (maxDistZ - proc.dist) >> 0, + itop; + + if (Wolf.ISXP && Wolf.ISFIREFOX) { + itop = (proc.texture % 2) ? 0 : -height; + } else { + itop = -(proc.texture-1) * height; + textureSrc = "art/walls-shaded/64/walls.png"; + } + + if (image._src != textureSrc) { + image._src = textureSrc; + if (useBackgroundImage) { + imgStyle.backgroundImage = "url(" + textureSrc + ")"; + } else { + image.src = textureSrc; + } + } + + if (slice._zIndex != z) { + sliceStyle.zIndex = slice._zIndex = z; + } + if (image._height != height) { + sliceStyle.height = (image._height = height) + "px"; + if (Wolf.ISXP && Wolf.ISFIREFOX) { + imgStyle.height = (height * 2) + "px"; + } else { + imgStyle.height = (height * 120) + "px"; + } + } + + if (image._itop != itop) { + imgStyle.top = (image._itop = itop) + "px"; + } + + if (image._top != top) { + sliceStyle.top = (image._top = top) + "px"; + } + if (image._left != left) { + imgStyle.left = (image._left = left) + "px"; + } + } + + function drawWall(n, viewport, tracePoint, level) { + var x = tracePoint.tileX, + y = tracePoint.tileY, + vx = POS2TILE(viewport.x), + vy = POS2TILE(viewport.y), + tileMap = level.tileMap, + proc = processTrace(viewport, tracePoint), + texture = proc.vert ? level.wallTexX[x][y] : level.wallTexY[x][y], + textureSrc; + + + // door sides + if (tracePoint.flags & TRACE_HIT_VERT) { + if (x >= vx && tileMap[x-1][y] & DOOR_TILE) { + texture = TEX_PLATE; + } + if (x < vx && tileMap[x+1][y] & DOOR_TILE) { + texture = TEX_PLATE; + } + } else { + if (y >= vy && tileMap[x][y-1] & DOOR_TILE) { + texture = TEX_PLATE; + } + if (y < vy && tileMap[x][y+1] & DOOR_TILE) { + texture = TEX_PLATE; + } + } + + texture++; + + proc.texture = texture; + + if (texture % 2 == 0) { + texture--; + } + textureSrc = texturePath + "w_" + texture + ".png"; + + updateSlice(n, textureSrc, proc); + } + + function drawDoor(n, viewport, tracePoint, level) { + var proc = processTrace(viewport, tracePoint), + texture, textureSrc; + + //texture = Wolf.TEX_DDOOR + 1; + texture = level.state.doorMap[tracePoint.tileX][tracePoint.tileY].texture + 1; + + proc.texture = texture; + + if (texture % 2 == 0) { + texture -= 1; + } + + textureSrc = texturePath + "w_" + texture + ".png"; + + updateSlice(n, textureSrc, proc); + } + + function drawSprites(viewport, level, visibleTiles) { + var vis, n, + dist, dx, dy, angle, + z, width, size, + div, image, + divStyle, imgStyle; + + + // build visible sprites list + visibleSprites = Wolf.Sprites.createVisList(viewport, level, visibleTiles); + + for (n = 0; n < visibleSprites.length; ++n ){ + vis = visibleSprites[n]; + dist = vis.dist; + + if (dist < MINDIST / 2 ) { + //continue; // little hack to save speed & z-buffer + } + + // make sure sprite is loaded + if (!vis.sprite.div) { + loadSprite(vis.sprite) + } + + div = vis.sprite.div; + divStyle = div.style; + + image = div.image; + imgStyle = image.style; + + dx = vis.sprite.x - viewport.x; + dy = vis.sprite.y - viewport.y; + angle = atan2(dy, dx) - FINE2RAD(viewport.angle); + + //dist = dist * Math.cos(angle); + + size = (VIEW_DIST / dist * TILEGLOBAL) >> 0; + + divStyle.display = "block"; + divStyle.width = size + "px"; + divStyle.height = size + "px"; + + divStyle.left = (XRES / 2 - size / 2 - tan(angle) * VIEW_DIST) + "px"; + + divStyle.top = (YRES / 2 - size / 2) + "px"; + + texture = Wolf.Sprites.getTexture(vis.sprite.tex[0]); + textureSrc = spritePath + texture.sheet; + + if (image._src != textureSrc) { + image._src = textureSrc; + if (useBackgroundImage) { + imgStyle.backgroundImage = "url(" + textureSrc + ")"; + } else { + image.src = textureSrc; + } + } + + z = (maxDistZ - dist) >> 0; + width = texture.num * size; + left = -texture.idx * size; + + if (div._zIndex != z) { + divStyle.zIndex = div._zIndex = z; + } + if (image._width != width) { + imgStyle.width = (image._width = width) + "px"; + } + if (image._height != size) { + imgStyle.height = (image._height = size) + "px"; + } + if (image._left != left) { + imgStyle.left = (image._left = left) + "px"; + } + } + } + + function unloadSprite(sprite) { + if (sprite.div) { + $(sprite.div).remove(); + sprite.div = null; + } + } + + function loadSprite(sprite) { + var div = document.createElement("div"), + image; + + div.style.display = "none"; + div.style.position = "absolute"; + div.style.width = "128px"; + div.style.height = "128px"; + div.style.overflow = "hidden"; + div.className = "sprite"; + + image = useBackgroundImage ? $("
") : $(""); + + image.css({ + position : "absolute", + display : "block", + top : 0, + height : "100%", + width : "100%", + backgroundSize : "100%", + backgroundRepeat : "no-repeat" + }); + + div.image = image[0]; + div.appendChild(div.image); + + sprite.div = div; + $("#game .renderer").append(div); + } + + return { + init : init, + draw : draw, + clear : clear, + loadSprite : loadSprite, + unloadSprite : unloadSprite, + reset : reset + }; + +})(); diff --git a/js/requestanimframe.js b/js/requestanimframe.js new file mode 100644 index 0000000..a5ba3cf --- /dev/null +++ b/js/requestanimframe.js @@ -0,0 +1,56 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + + +/* requestAnimationFrame polyfill */ +(function() { + + window.requestAnimationFrame = (function() { + return window.requestAnimationFrame + || window.webkitRequestAnimationFrame + || window.mozRequestAnimationFrame + || window.oRequestAnimationFrame + || window.msRequestAnimationFrame + || function(callback, element) { + return window.setTimeout( + function() { + callback(Date.now()); + }, 1000 / 60 + ); + }; + })(); + + window.cancelRequestAnimationFrame = (function() { + return window.cancelRequestAnimationFrame + || window.webkitCancelRequestAnimationFrame + || window.mozCancelRequestAnimationFrame + || window.oCancelRequestAnimationFrame + || window.msCancelRequestAnimationFrame + || window.clearTimeout; + })(); + +})(); + diff --git a/js/sound.js b/js/sound.js new file mode 100644 index 0000000..1400893 --- /dev/null +++ b/js/sound.js @@ -0,0 +1,208 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +Wolf.Sound = (function() { + + Wolf.setConsts({ + // Sound channels + // Channel 0 never willingly overrides + // Other channels (1-7) always override a playing sound on that channel + CHAN_AUTO : 0, + CHAN_WEAPON : 1, + CHAN_VOICE : 2, + CHAN_ITEM : 3, + CHAN_BODY : 4, + // Modifier flags + CHAN_NO_PHS_ADD : 8, // Send to all clients, not just ones in PHS (ATTN 0 will also do this) + CHAN_RELIABLE : 16, // Send by reliable message, not datagram + // Sound attenuation values + ATTN_NONE : 0, // Full volume the entire level + ATTN_NORM : 1, + ATTN_IDLE : 2, + ATTN_STATIC : 3, // Diminish very rapidly with distance + + MAX_PLAYSOUNDS : 128, + MAX_CHANNELS : 64, + + MUSIC_VOLUME : 0.8, + MASTER_VOLUME : 0.6 + }); + + var sounds = {}, + audioElements = [], + currentMusic, + soundEnabled = true, + musicEnabled = true, + music, + ext, + exts = ["ogg", "mp3"]; + + function getFileName(file) { + if (!ext) { + // look for a probably + for (var i=0;i 0) { + audioElements[i].currentTime = 0; + audioElements[i].pause(); + } + } + } + + function init() { + } + + + function isMusicEnabled() { + return musicEnabled + } + + function isSoundEnabled() { + return soundEnabled; + } + + function toggleMusic(enable) { + if (typeof enable != "undefined") { + musicEnabled = enable; + } else { + musicEnabled = !musicEnabled; + } + if (music) { + music.volume = Wolf.MUSIC_VOLUME * Wolf.MASTER_VOLUME * (musicEnabled ? 1 : 0); + } + } + + function pauseMusic(enable) { + if (music) { + if (enable) { + music.pause(); + } else if (music.paused) { + music.play(); + } + } + } + + function toggleSound(enable) { + if (typeof enable != "undefined") { + soundEnabled = enable; + } else { + soundEnabled = !soundEnabled; + } + } + + if (Modernizr.audio) { + return { + startSound : startSound, + startMusic : startMusic, + stopAllSounds : stopAllSounds, + isMusicEnabled : isMusicEnabled, + isSoundEnabled : isSoundEnabled, + toggleMusic : toggleMusic, + toggleSound : toggleSound, + pauseMusic : pauseMusic, + init : init + } + } else { + return { + startSound : Wolf.noop, + startMusic : Wolf.noop, + stopAllSounds : Wolf.noop, + isMusicEnabled : Wolf.noop, + isSoundEnabled : Wolf.noop, + toggleMusic : Wolf.noop, + toggleSound : Wolf.noop, + pauseMusic : Wolf.noop, + init : Wolf.noop + } + } +})(); \ No newline at end of file diff --git a/js/sprites.js b/js/sprites.js new file mode 100644 index 0000000..945aa11 --- /dev/null +++ b/js/sprites.js @@ -0,0 +1,1085 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +Wolf.Sprites = (function() { + var spriteTextures = []; + // + // sprite constants + // + var spriteNames = [ + "SPR_DEMO", + "SPR_DEATHCAM", + // + // static sprites + // + // 002 + "SPR_STAT_0", "SPR_STAT_1","SPR_STAT_2", "SPR_STAT_3", + "SPR_STAT_4", "SPR_STAT_5","SPR_STAT_6", "SPR_STAT_7", + "SPR_STAT_8", "SPR_STAT_9","SPR_STAT_10","SPR_STAT_11", + "SPR_STAT_12","SPR_STAT_13","SPR_STAT_14","SPR_STAT_15", + "SPR_STAT_16","SPR_STAT_17","SPR_STAT_18","SPR_STAT_19", + "SPR_STAT_20","SPR_STAT_21","SPR_STAT_22","SPR_STAT_23", + "SPR_STAT_24","SPR_STAT_25","SPR_STAT_26","SPR_STAT_27", + "SPR_STAT_28","SPR_STAT_29","SPR_STAT_30","SPR_STAT_31", + "SPR_STAT_32","SPR_STAT_33","SPR_STAT_34","SPR_STAT_35", + "SPR_STAT_36","SPR_STAT_37","SPR_STAT_38","SPR_STAT_39", + "SPR_STAT_40","SPR_STAT_41","SPR_STAT_42","SPR_STAT_43", + "SPR_STAT_44","SPR_STAT_45","SPR_STAT_46","SPR_STAT_47", + "SPR_STAT_48","SPR_STAT_49","SPR_STAT_50","SPR_STAT_51", + // + // Guard + // + // 054 + "SPR_GRD_S_1","SPR_GRD_S_2","SPR_GRD_S_3","SPR_GRD_S_4", + "SPR_GRD_S_5","SPR_GRD_S_6","SPR_GRD_S_7","SPR_GRD_S_8", + + "SPR_GRD_W1_1","SPR_GRD_W1_2","SPR_GRD_W1_3","SPR_GRD_W1_4", + "SPR_GRD_W1_5","SPR_GRD_W1_6","SPR_GRD_W1_7","SPR_GRD_W1_8", + + "SPR_GRD_W2_1","SPR_GRD_W2_2","SPR_GRD_W2_3","SPR_GRD_W2_4", + "SPR_GRD_W2_5","SPR_GRD_W2_6","SPR_GRD_W2_7","SPR_GRD_W2_8", + + "SPR_GRD_W3_1","SPR_GRD_W3_2","SPR_GRD_W3_3","SPR_GRD_W3_4", + "SPR_GRD_W3_5","SPR_GRD_W3_6","SPR_GRD_W3_7","SPR_GRD_W3_8", + + "SPR_GRD_W4_1","SPR_GRD_W4_2","SPR_GRD_W4_3","SPR_GRD_W4_4", + "SPR_GRD_W4_5","SPR_GRD_W4_6","SPR_GRD_W4_7","SPR_GRD_W4_8", + + "SPR_GRD_PAIN_1","SPR_GRD_DIE_1","SPR_GRD_DIE_2","SPR_GRD_DIE_3", + "SPR_GRD_PAIN_2","SPR_GRD_DEAD", + + "SPR_GRD_SHOOT1","SPR_GRD_SHOOT2","SPR_GRD_SHOOT3", + // + // Dog + // + // 103 + "SPR_DOG_W1_1","SPR_DOG_W1_2","SPR_DOG_W1_3","SPR_DOG_W1_4", + "SPR_DOG_W1_5","SPR_DOG_W1_6","SPR_DOG_W1_7","SPR_DOG_W1_8", + + "SPR_DOG_W2_1","SPR_DOG_W2_2","SPR_DOG_W2_3","SPR_DOG_W2_4", + "SPR_DOG_W2_5","SPR_DOG_W2_6","SPR_DOG_W2_7","SPR_DOG_W2_8", + + "SPR_DOG_W3_1","SPR_DOG_W3_2","SPR_DOG_W3_3","SPR_DOG_W3_4", + "SPR_DOG_W3_5","SPR_DOG_W3_6","SPR_DOG_W3_7","SPR_DOG_W3_8", + + "SPR_DOG_W4_1","SPR_DOG_W4_2","SPR_DOG_W4_3","SPR_DOG_W4_4", + "SPR_DOG_W4_5","SPR_DOG_W4_6","SPR_DOG_W4_7","SPR_DOG_W4_8", + + "SPR_DOG_DIE_1","SPR_DOG_DIE_2","SPR_DOG_DIE_3","SPR_DOG_DEAD", + "SPR_DOG_JUMP1","SPR_DOG_JUMP2","SPR_DOG_JUMP3", + // + // SS + // + // 142 + "SPR_SS_S_1","SPR_SS_S_2","SPR_SS_S_3","SPR_SS_S_4", + "SPR_SS_S_5","SPR_SS_S_6","SPR_SS_S_7","SPR_SS_S_8", + + "SPR_SS_W1_1","SPR_SS_W1_2","SPR_SS_W1_3","SPR_SS_W1_4", + "SPR_SS_W1_5","SPR_SS_W1_6","SPR_SS_W1_7","SPR_SS_W1_8", + + "SPR_SS_W2_1","SPR_SS_W2_2","SPR_SS_W2_3","SPR_SS_W2_4", + "SPR_SS_W2_5","SPR_SS_W2_6","SPR_SS_W2_7","SPR_SS_W2_8", + + "SPR_SS_W3_1","SPR_SS_W3_2","SPR_SS_W3_3","SPR_SS_W3_4", + "SPR_SS_W3_5","SPR_SS_W3_6","SPR_SS_W3_7","SPR_SS_W3_8", + + "SPR_SS_W4_1","SPR_SS_W4_2","SPR_SS_W4_3","SPR_SS_W4_4", + "SPR_SS_W4_5","SPR_SS_W4_6","SPR_SS_W4_7","SPR_SS_W4_8", + + "SPR_SS_PAIN_1","SPR_SS_DIE_1","SPR_SS_DIE_2","SPR_SS_DIE_3", + "SPR_SS_PAIN_2","SPR_SS_DEAD", + + "SPR_SS_SHOOT1","SPR_SS_SHOOT2","SPR_SS_SHOOT3", + // + // Mutant + // + // 191 + "SPR_MUT_S_1","SPR_MUT_S_2","SPR_MUT_S_3","SPR_MUT_S_4", + "SPR_MUT_S_5","SPR_MUT_S_6","SPR_MUT_S_7","SPR_MUT_S_8", + + "SPR_MUT_W1_1","SPR_MUT_W1_2","SPR_MUT_W1_3","SPR_MUT_W1_4", + "SPR_MUT_W1_5","SPR_MUT_W1_6","SPR_MUT_W1_7","SPR_MUT_W1_8", + + "SPR_MUT_W2_1","SPR_MUT_W2_2","SPR_MUT_W2_3","SPR_MUT_W2_4", + "SPR_MUT_W2_5","SPR_MUT_W2_6","SPR_MUT_W2_7","SPR_MUT_W2_8", + + "SPR_MUT_W3_1","SPR_MUT_W3_2","SPR_MUT_W3_3","SPR_MUT_W3_4", + "SPR_MUT_W3_5","SPR_MUT_W3_6","SPR_MUT_W3_7","SPR_MUT_W3_8", + + "SPR_MUT_W4_1","SPR_MUT_W4_2","SPR_MUT_W4_3","SPR_MUT_W4_4", + "SPR_MUT_W4_5","SPR_MUT_W4_6","SPR_MUT_W4_7","SPR_MUT_W4_8", + + "SPR_MUT_PAIN_1","SPR_MUT_DIE_1","SPR_MUT_DIE_2","SPR_MUT_DIE_3", + "SPR_MUT_PAIN_2","SPR_MUT_DIE_4","SPR_MUT_DEAD", + + "SPR_MUT_SHOOT1","SPR_MUT_SHOOT2","SPR_MUT_SHOOT3","SPR_MUT_SHOOT4", + // + // Officer + // + // 242 + "SPR_OFC_S_1","SPR_OFC_S_2","SPR_OFC_S_3","SPR_OFC_S_4", + "SPR_OFC_S_5","SPR_OFC_S_6","SPR_OFC_S_7","SPR_OFC_S_8", + + "SPR_OFC_W1_1","SPR_OFC_W1_2","SPR_OFC_W1_3","SPR_OFC_W1_4", + "SPR_OFC_W1_5","SPR_OFC_W1_6","SPR_OFC_W1_7","SPR_OFC_W1_8", + + "SPR_OFC_W2_1","SPR_OFC_W2_2","SPR_OFC_W2_3","SPR_OFC_W2_4", + "SPR_OFC_W2_5","SPR_OFC_W2_6","SPR_OFC_W2_7","SPR_OFC_W2_8", + + "SPR_OFC_W3_1","SPR_OFC_W3_2","SPR_OFC_W3_3","SPR_OFC_W3_4", + "SPR_OFC_W3_5","SPR_OFC_W3_6","SPR_OFC_W3_7","SPR_OFC_W3_8", + + "SPR_OFC_W4_1","SPR_OFC_W4_2","SPR_OFC_W4_3","SPR_OFC_W4_4", + "SPR_OFC_W4_5","SPR_OFC_W4_6","SPR_OFC_W4_7","SPR_OFC_W4_8", + + "SPR_OFC_PAIN_1","SPR_OFC_DIE_1","SPR_OFC_DIE_2","SPR_OFC_DIE_3", + "SPR_OFC_PAIN_2","SPR_OFC_DIE_4","SPR_OFC_DEAD", + + "SPR_OFC_SHOOT1","SPR_OFC_SHOOT2","SPR_OFC_SHOOT3", + // + // Ghosts + // + // 292 + "SPR_BLINKY_W1","SPR_BLINKY_W2","SPR_PINKY_W1","SPR_PINKY_W2", + "SPR_CLYDE_W1","SPR_CLYDE_W2","SPR_INKY_W1","SPR_INKY_W2", + // + // Hans + // + // 300 + "SPR_BOSS_W1","SPR_BOSS_W2","SPR_BOSS_W3","SPR_BOSS_W4", + "SPR_BOSS_SHOOT1","SPR_BOSS_SHOOT2","SPR_BOSS_SHOOT3","SPR_BOSS_DEAD", + + "SPR_BOSS_DIE1","SPR_BOSS_DIE2","SPR_BOSS_DIE3", + // + // Schabbs + // + // 311 + "SPR_SCHABB_W1","SPR_SCHABB_W2","SPR_SCHABB_W3","SPR_SCHABB_W4", + "SPR_SCHABB_SHOOT1","SPR_SCHABB_SHOOT2", + + "SPR_SCHABB_DIE1","SPR_SCHABB_DIE2","SPR_SCHABB_DIE3","SPR_SCHABB_DEAD", + "SPR_HYPO1","SPR_HYPO2","SPR_HYPO3","SPR_HYPO4", + // + // Fake + // + // 325 + "SPR_FAKE_W1","SPR_FAKE_W2","SPR_FAKE_W3","SPR_FAKE_W4", + "SPR_FAKE_SHOOT","SPR_FIRE1","SPR_FIRE2", + + "SPR_FAKE_DIE1","SPR_FAKE_DIE2","SPR_FAKE_DIE3","SPR_FAKE_DIE4", + "SPR_FAKE_DIE5","SPR_FAKE_DEAD", + // + // Hitler + // + // 338 + "SPR_MECHA_W1","SPR_MECHA_W2","SPR_MECHA_W3","SPR_MECHA_W4", + "SPR_MECHA_SHOOT1","SPR_MECHA_SHOOT2","SPR_MECHA_SHOOT3","SPR_MECHA_DEAD", + + "SPR_MECHA_DIE1","SPR_MECHA_DIE2","SPR_MECHA_DIE3", + + "SPR_HITLER_W1","SPR_HITLER_W2","SPR_HITLER_W3","SPR_HITLER_W4", + "SPR_HITLER_SHOOT1","SPR_HITLER_SHOOT2","SPR_HITLER_SHOOT3","SPR_HITLER_DEAD", + + "SPR_HITLER_DIE1","SPR_HITLER_DIE2","SPR_HITLER_DIE3","SPR_HITLER_DIE4", + "SPR_HITLER_DIE5","SPR_HITLER_DIE6","SPR_HITLER_DIE7", + // + // Giftmacher + // + // 364 + "SPR_GIFT_W1","SPR_GIFT_W2","SPR_GIFT_W3","SPR_GIFT_W4", + "SPR_GIFT_SHOOT1","SPR_GIFT_SHOOT2", + + "SPR_GIFT_DIE1","SPR_GIFT_DIE2","SPR_GIFT_DIE3","SPR_GIFT_DEAD", + // + // Rocket, smoke and small explosion + // + // 374 + "SPR_ROCKET_1","SPR_ROCKET_2","SPR_ROCKET_3","SPR_ROCKET_4", + "SPR_ROCKET_5","SPR_ROCKET_6","SPR_ROCKET_7","SPR_ROCKET_8", + + "SPR_SMOKE_1","SPR_SMOKE_2","SPR_SMOKE_3","SPR_SMOKE_4", + "SPR_BOOM_1","SPR_BOOM_2","SPR_BOOM_3", + // + // Angel of Death's DeathSparks(tm) + // + // 389 + "SPR_HROCKET_1","SPR_HROCKET_2","SPR_HROCKET_3","SPR_HROCKET_4", + "SPR_HROCKET_5","SPR_HROCKET_6","SPR_HROCKET_7","SPR_HROCKET_8", + + "SPR_HSMOKE_1","SPR_HSMOKE_2","SPR_HSMOKE_3","SPR_HSMOKE_4", + "SPR_HBOOM_1","SPR_HBOOM_2","SPR_HBOOM_3", + + "SPR_SPARK1","SPR_SPARK2","SPR_SPARK3","SPR_SPARK4", + // + // Gretel + // + // 408 + "SPR_GRETEL_W1","SPR_GRETEL_W2","SPR_GRETEL_W3","SPR_GRETEL_W4", + "SPR_GRETEL_SHOOT1","SPR_GRETEL_SHOOT2","SPR_GRETEL_SHOOT3","SPR_GRETEL_DEAD", + + "SPR_GRETEL_DIE1","SPR_GRETEL_DIE2","SPR_GRETEL_DIE3", + // + // Fat Face + // + // 419 + "SPR_FAT_W1","SPR_FAT_W2","SPR_FAT_W3","SPR_FAT_W4", + "SPR_FAT_SHOOT1","SPR_FAT_SHOOT2","SPR_FAT_SHOOT3","SPR_FAT_SHOOT4", + + "SPR_FAT_DIE1","SPR_FAT_DIE2","SPR_FAT_DIE3","SPR_FAT_DEAD", + // + // bj + // + // 431 + "SPR_BJ_W1","SPR_BJ_W2","SPR_BJ_W3","SPR_BJ_W4", + "SPR_BJ_JUMP1","SPR_BJ_JUMP2","SPR_BJ_JUMP3","SPR_BJ_JUMP4", + // + // SPEAR OF DESTINY + // + + // + // Trans Grosse + // + // 439 + "SPR_TRANS_W1","SPR_TRANS_W2","SPR_TRANS_W3","SPR_TRANS_W4", + "SPR_TRANS_SHOOT1","SPR_TRANS_SHOOT2","SPR_TRANS_SHOOT3","SPR_TRANS_DEAD", + + "SPR_TRANS_DIE1","SPR_TRANS_DIE2","SPR_TRANS_DIE3", + // + // Wilhelm + // + // 450 + "SPR_WILL_W1","SPR_WILL_W2","SPR_WILL_W3","SPR_WILL_W4", + "SPR_WILL_SHOOT1","SPR_WILL_SHOOT2","SPR_WILL_SHOOT3","SPR_WILL_SHOOT4", + + "SPR_WILL_DIE1","SPR_WILL_DIE2","SPR_WILL_DIE3","SPR_WILL_DEAD", + // + // UberMutant + // + // 462 + "SPR_UBER_W1","SPR_UBER_W2","SPR_UBER_W3","SPR_UBER_W4", + "SPR_UBER_SHOOT1","SPR_UBER_SHOOT2","SPR_UBER_SHOOT3","SPR_UBER_SHOOT4", + + "SPR_UBER_DIE1","SPR_UBER_DIE2","SPR_UBER_DIE3","SPR_UBER_DIE4", + "SPR_UBER_DEAD", + // + // Death Knight + // + // 475 + "SPR_DEATH_W1","SPR_DEATH_W2","SPR_DEATH_W3","SPR_DEATH_W4", + "SPR_DEATH_SHOOT1","SPR_DEATH_SHOOT2","SPR_DEATH_SHOOT3","SPR_DEATH_SHOOT4", + + "SPR_DEATH_DIE1","SPR_DEATH_DIE2","SPR_DEATH_DIE3","SPR_DEATH_DIE4", + "SPR_DEATH_DIE5","SPR_DEATH_DIE6","SPR_DEATH_DEAD", + // + // Ghost + // + // 490 + "SPR_SPECTRE_W1","SPR_SPECTRE_W2","SPR_SPECTRE_W3","SPR_SPECTRE_W4", + "SPR_SPECTRE_F1","SPR_SPECTRE_F2","SPR_SPECTRE_F3","SPR_SPECTRE_F4", + // + // Angel of Death + // + // 498 + "SPR_ANGEL_W1","SPR_ANGEL_W2","SPR_ANGEL_W3","SPR_ANGEL_W4", + "SPR_ANGEL_SHOOT1","SPR_ANGEL_SHOOT2","SPR_ANGEL_TIRED1","SPR_ANGEL_TIRED2", + + "SPR_ANGEL_DIE1","SPR_ANGEL_DIE2","SPR_ANGEL_DIE3","SPR_ANGEL_DIE4", + "SPR_ANGEL_DIE5","SPR_ANGEL_DIE6","SPR_ANGEL_DIE7","SPR_ANGEL_DEAD", + // + // player attack frames + // + // 514 + "SPR_KNIFEREADY","SPR_KNIFEATK1","SPR_KNIFEATK2","SPR_KNIFEATK3", + "SPR_KNIFEATK4", + + "SPR_PISTOLREADY","SPR_PISTOLATK1","SPR_PISTOLATK2","SPR_PISTOLATK3", + "SPR_PISTOLATK4", + + "SPR_MACHINEGUNREADY","SPR_MACHINEGUNATK1","SPR_MACHINEGUNATK2","MACHINEGUNATK3", + "SPR_MACHINEGUNATK4", + + "SPR_CHAINREADY","SPR_CHAINATK1","SPR_CHAINATK2","SPR_CHAINATK3", + "SPR_CHAINATK4" + ]; + + var spriteConsts = {}; + for (var i=0,n=spriteNames.length;i>TILESHIFT) + // but also (x>>TILESHIFT)-1 if (x%TILEWIDTH)= Wolf.MAX_SPRITES) { + Wolf.log("Warning n_of_sprt == MAX_SPRITES"); + return -1; + } + */ + + Wolf.Renderer.loadSprite(newSprite); + + level.sprites.push(newSprite); + return newSprite; + + //level.numSprites++ + //return level.numSprites-1; + } + + function setPos(level, sprite, x, y, angle) { + /* + if (sprite_id == -1) { + return; + } + */ + + //var sprite = level.sprites[sprite_id]; + + sprite.x = x; + sprite.y = y; + sprite.angle = angle; + sprite.tile.x = Wolf.POS2TILE( x ); + sprite.tile.y = Wolf.POS2TILE( y ); + sprite.flags |= Wolf.SPRT_CHG_POS; + + if (!(x & Wolf.HALFTILE)) { // (x%TILEGLOBAL>=HALFTILE) + sprite.tile.x--; + } + + if (!(y & Wolf.HALFTILE)) { + sprite.tile.y--; + } + } + + function setTex(level, sprite, index, tex) { + /* + if (sprite_id == -1) { + return; + } + */ + + //cacheTextures(tex, tex); + + if (index == -1) { // one texture for each phase + sprite.tex[0] = tex; + sprite.flags |= Wolf.SPRT_ONE_TEX; + } else { + sprite.tex[index] = tex; + } + sprite.flags |= Wolf.SPRT_CHG_TEX; + } + + function cacheTextures(start, end) { + var i, texname; + + for( i = start ; i <= end ; ++i ) { + if (!spriteTextures[i]) { + //texname = "sprites/" + () + ".png"; + //spriteTextures[i] = TM_FindTexture( texname, TT_Sprite ); + } + } + } + + function getTexture(id) { + return sheets[id]; + } + + + function createVisList(viewport, level, visibleTiles) { + var tx, ty, n, num, numVisible, + vislist, + sprt; + + vislist = []; + numVisible = 0; + + for (n=0, num=level.sprites.length; n < num; ++n) { + sprt = level.sprites[n]; + if (sprt.flags & Wolf.SPRT_REMOVE) { + continue; + } + + tx = sprt.tile.x; + ty = sprt.tile.y; + + if (tx > 63) { + tx = 63; + } + if (ty > 63) { + ty = 63; + } + + // can be in any of 4 surrounding tiles; not 9 - see definition of tilex & tiley + if (visibleTiles[tx][ty] || visibleTiles[tx + 1][ty] || visibleTiles[tx][ty + 1] || visibleTiles[tx + 1][ty + 1]) { + + // player spoted it + var vis = vislist[vislist.length] = {}; + + vis.dist = Wolf.Math.lineLen2Point(sprt.x - viewport.x, sprt.y - viewport.y, viewport.angle); + vis.x = sprt.x; + vis.y = sprt.y; + vis.angle = sprt.angle; + vis.tex = sprt.tex[0]; //FIXME! + vis.sprite = sprt; + + if(++numVisible > Wolf.MAX_VIS_SPRITES) { + break; // vislist full + } + } + } + + + // sorting list + if (numVisible) { // do not sort if no entries + //vislist.sort(); + //qsort( vislist, numVisible, sizeof( visobj_t ), Sprite_cmpVis ); + } + + return vislist; + } + + function remove(level, sprite) { + if (!sprite) { + return; + } + + sprite.flags |= Wolf.SPRT_REMOVE; + Wolf.Renderer.unloadSprite(sprite); + } + + function clean(level) { + var i, num, + liveSprites = []; + + for (i=0, num=level.sprites.length; i < num; ++i) { + if (level.sprites[i].flags & Wolf.SPRT_REMOVE) { + continue; + } + liveSprites.push(level.sprites[i]); + } + level.sprites = liveSprites; + } + + return { + getNewSprite : getNewSprite, + setPos : setPos, + setTex : setTex, + cacheTextures : cacheTextures, + getTexture : getTexture, + createVisList : createVisList, + remove : remove, + clean : clean + }; + +})(); \ No newline at end of file diff --git a/js/weapon.js b/js/weapon.js new file mode 100644 index 0000000..d495461 --- /dev/null +++ b/js/weapon.js @@ -0,0 +1,175 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** + * @namespace + * @description Weapons + */ +Wolf.Weapon = (function() { + + + function fireHit(game, player) { + var level = game.level, + closest, + dist, + d1, + n, + shotDist, + damage, + guard; + + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "lsfx/023.wav", 1, Wolf.ATTN_NORM, 0); + + // actually fire + dist = 0x7fffffff; + closest = null; + + for (n=0; n (2 * Wolf.TILEGLOBAL / 3)) { + continue; // miss + } + + d1 = Wolf.Math.lineLen2Point(guard.x - player.position.x, guard.y - player.position.y, player.angle); + + if (d1 < 0 || d1 > dist) { + continue; + } + + if (!Wolf.Level.checkLine(guard.x, guard.y, player.position.x, player.position.y, level)) { + continue; // obscured + } + dist = d1; + closest = guard; + } + } + + if (!closest || dist > Wolf.TILE2POS(1)) { + return; // missed if further than 1.5 tiles + } + + damage = Wolf.Random.rnd() >> 4; + + Wolf.ActorAI.damageActor(closest, game, player, damage); // hit something + } + + + function fireLead(game, player) { + var level = game.level, + closest, + damage, + dx, dy, dist, + d1, shotDist, n, + guard; + + switch (player.weapon) { + case Wolf.WEAPON_PISTOL: + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "sfx/012.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.WEAPON_AUTO: + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "sfx/011.wav", 1, Wolf.ATTN_NORM, 0); + break; + + case Wolf.WEAPON_CHAIN: + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_WEAPON, "sfx/013.wav", 1, Wolf.ATTN_NORM, 0); + break; + } + + player.madenoise = true; + + dist = 0x7fffffff; + closest = null; + + for (n=0;n < level.state.numGuards; ++n) { + guard = level.state.guards[n]; + if (guard.flags & Wolf.FL_SHOOTABLE ) { // && Guards[n].flags&FL_VISABLE + shotDist = Wolf.Math.point2LineDist(guard.x - player.position.x, guard.y - player.position.y, player.angle); + if (shotDist > (2 * Wolf.TILEGLOBAL / 3)) { + continue; // miss + } + + d1 = Wolf.Math.lineLen2Point(guard.x - player.position.x, guard.y - player.position.y, player.angle); + if (d1 < 0 || d1 > dist) { + continue; + } + if (!Wolf.Level.checkLine(guard.x, guard.y, player.position.x, player.position.y, level)) { + continue; // obscured + } + + dist = d1; + closest = guard; + } + } + + if (!closest) { // missed + var tracePoint = { + angle : Wolf.Math.normalizeAngle(player.angle - Wolf.DEG2FINE(2) + (Math.random() * 0x10000) % (Wolf.DEG2FINE(4))), + x : player.position.x, + y : player.position.y, + flags : Wolf.TRACE_BULLET + } + + Wolf.Raycaster.trace(level, null, tracePoint); + + if (tracePoint.flags & Wolf.TRACE_HIT_DOOR) { + Wolf.Sound.startSound(null, null, 0, Wolf.CHAN_AUTO, "lsfx/028.wav", 1, Wolf.ATTN_NORM, 0); + } + + return; + } + + // hit something + dx = Math.abs(closest.tile.x - player.tile.x); + dy = Math.abs(closest.tile.y - player.tile.y); + dist = Math.max(dx, dy); + + if (dist < 2) { + damage = Wolf.Random.rnd() / 4; + } else if (dist < 4) { + damage = Wolf.Random.rnd() / 6; + } else { + if (Wolf.Random.rnd() / 12 < dist) { + return; // missed + } + damage = Wolf.Random.rnd() / 6; + } + + Wolf.ActorAI.damageActor(closest, game, player, damage); + } + + + + return { + fireHit : fireHit, + fireLead : fireLead + }; + + +})(); \ No newline at end of file diff --git a/js/wolf.js b/js/wolf.js new file mode 100644 index 0000000..6f7ca54 --- /dev/null +++ b/js/wolf.js @@ -0,0 +1,117 @@ +/* +* =========================================================================== +* +* Wolf3D Browser Version GPL Source Code +* Copyright (C) 2012 id Software LLC, a ZeniMax Media company. +* +* This file is part of the Wolf3D Browser Version GPL Source Code ("Wolf3D Browser Source Code"). +* +* Wolf3D Browser Source Code is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* Wolf3D Browser Source Code is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License version 2 +* along with Wolf3D Browser Source Code. If not, see . +* +* 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. +* +* =========================================================================== +*/ + +/** @namespace */ +var Wolf = { + + XRES : 608, + YRES : 304, + SLICE_WIDTH : 3, + WALL_TEXTURE_WIDTH : 64, + NUM_WALL_TEXTURES : 55, + HUD_FACE_WIDTH : 48, + HUD_FACE_HEIGHT : 64, + HUD_WEAPON_WIDTH : 256, + + + NUMAREAS : 37, // number of areas + FIRSTAREA : 0x6B, // first area in map data (it is by the way a way to the secret floor!) + AMBUSHTILE : 0x6A, // def guard + AMBUSH : -2, + + TILEGLOBAL : 0x10000, + HALFTILE : 0x8000, + TILESHIFT : 16, + MINDIST : 0x5800, + FLOATTILE : 65536.0, + + TILE2POS : function(a) { return (((a)<>Wolf.TILESHIFT); }, + POS2TILEf : function(a) { return ((a)/Wolf.FLOATTILE); }, + + ASTEP : 0.0078125, // 1 FINE=x DEGREES + ASTEPRAD : 0.000136354, // 1 FINE=x RADIANS + ANG_1RAD : 7333.8598, // 1 RADIAN=x FINES + ANG_0 : 0, //(int)((float)0/ASTEP) + ANG_1 : 128, //(int)((float)1/ASTEP) + ANG_6 : 768, //(int)((float)6/ASTEP) + ANG_15 : 1920, //(int)((float)15/ASTEP) + ANG_22_5 : 2880, //(int)((float)22.5/ASTEP) + ANG_30 : 3840, //(int)((float)30/ASTEP) + ANG_45 : 5760, //(int)((float)45/ASTEP) + ANG_67_5 : 8640, //(int)((float)67.5/ASTEP) + ANG_90 : 11520, //(int)((float)90/ASTEP) + ANG_112_5 : 14400, //(int)((float)112.5/ASTEP) + ANG_135 : 17280, //(int)((float)135/ASTEP) + ANG_157_5 : 20160, //(int)((float)157.5/ASTEP) + ANG_180 : 23040, //(int)((float)180/ASTEP) + ANG_202_5 : 25920, //(int)((float)202.5/ASTEP) + ANG_225 : 28800, //(int)((float)225/ASTEP) + ANG_247_5 : 31680, //(int)((float)247.5/ASTEP) + ANG_270 : 34560, //(int)((float)270/ASTEP) + ANG_292_5 : 37440, //(int)((float)292.5/ASTEP) + ANG_315 : 40320, //(int)((float)225/ASTEP) + ANG_337_5 : 43200, //(int)((float)337.5/ASTEP) + ANG_360 : 46080, //(int)((float)360/ASTEP) + + ANGLES : 360, // must be divisable by 4 + DEATHROTATE : 2, + + FINE2RAD : function(a) { return (a * Math.PI / Wolf.ANG_180); }, + RAD2FINE : function(a) { return (a * Wolf.ANG_180 / Math.PI); }, + FINE2DEG : function(a) { return (a / Wolf.ANG_1) >> 0; }, // !@# don't lose precision bits + FINE2DEGf : function(a) { return (a / Wolf.ANG_1); }, + DEG2FINE : function(a) { return (a * Wolf.ANG_1); } + +}; + +Wolf.setConsts = function(C) { + for (var a in C) { + if (C.hasOwnProperty(a) && !(a in Wolf)) { + Wolf[a] = C[a]; + } + } +}; + +Wolf.noop = function() {}; + +Wolf.log = function(str) { + /* + if (typeof console != "undefined") { + var t = new Date(), + e = new Error(), + f = ""; + if (typeof str == "object" && typeof e.stack == "string") { + // ugly hack to get some kind of reference to where the log call originated + var s = e.stack.split("\n")[2]+"", + m = s.match(/at (.*)$/); + f = m ? "\t[" + m[1] + "]" : ""; + } + console.log(t.toLocaleTimeString() + ": " + str + f); + } + */ +}; + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..939898c --- /dev/null +++ b/styles.css @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2012 id Software LLC, a ZeniMax Media company. + * + * This file is part of the WOLF3D Browser Version GPL Source Code. + * + */ + +html { + padding : 0; + background-color : black; +} + +body { + margin : 0; + padding : 0; + -webkit-touch-callout:none; + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-text-size-adjust: none; + + -webkit-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; + + width : 100%; + height : 100%; +} + +.load-progress { + position : absolute; + left : 0; + bottom : 0; + height : 5px; + width : 0; + background-color : #666; +} + + +#main { + position : absolute; + left : 0; + top : 0; + width : 640px; + height : 400px; + left : 50%; + top : 50%; + margin-left : -320px; + margin-top : -200px; + overflow : hidden; +} + +#game, #menu, #title-screen { + position : absolute; + left : 0; + top : 0; + width : 100%; + height : 100%; + display : none; + background-repeat : no-repeat; +} + +#title-screen { + background-image : url(art/title.png); + display : block; +} + +#game { + background-color : rgb(0,56,56); + background-image : url(art/gamebg.png); +} + + + +#game .loading { + background-color : rgb(0,56,56); + display : none; + position : absolute; + left : 0; + top : 0; + width : 100%; + height : 320px; + z-index : 60; +} +#game .loading img { + position : absolute; + left : 50%; + top : 50%; + margin-left : -224px; + margin-top : -48px; +} + + +#game .renderer { + z-index : 50; + background-color : #222; + overflow : hidden; + position : absolute; + left : 16px; + top : 8px; + cursor : crosshair; +} + +#game *, +#game .renderer div, +#game .renderer div img, +#game .renderer .sprite, +#game .renderer .sprite img { + image-rendering : optimizeSpeed; + image-rendering : -moz-crisp-edges; + image-rendering : -o-crisp-edges; + image-rendering : optimize-contrast; + image-rendering : -webkit-optimize-contrast; + -ms-interpolation-mode: nearest-neighbor; +} + +#game .renderer .player-weapon { + z-index : 100000000; + width : 256px; + height : 256px; + position : absolute; + bottom : 0; + left : 50%; + margin-left : -128px; + background-image : url(art/attack.png); + background-repeat : no-repeat; +} + + +#game .renderer .overlay { + z-index : 200000000; + width : 100%; + height : 100%; + position : absolute; + top : 0; + left : 0; + display : none; +} + +#game .renderer .damage-flash { + background : rgba(255,0,0,0.25); +} +#game .renderer .bonus-flash { + background : rgba(255,255,128,0.20); +} +#game .renderer .death { + background : rgba(255,0,0,0); +} + +#game .renderer .pause { + background : rgba(32,32,32,0.5); +} +#game .renderer .pause img { + position : absolute; + left : 50%; + top : 50%; + margin-left : -64px; + margin-top : -32px; +} + + +#game .ceiling, #game .floor { + position : absolute; + z-index : 0; + left : 0; + width : 100%; + height : 50%; +} + +#game .ceiling { + top : 0; +} + +#game .floor{ + top : 50%; +} + +#game .hud { + position : absolute; + z-index : 100; + bottom : 0; + width : 640px; + height : 80px; + background-image : url(art/hudbg.png); +} + +#game .hud .bj { + position : absolute; + width : 48px; + height : 64px; + left : 273px; + top : 9px; + overflow : hidden; + background-image : url(art/bj.png); +} + +#game .hud .key1, +#game .hud .key2 { + position : absolute; + width : 16px; + height : 32px; + left : 480px; + overflow : hidden; + background-image : url(art/hudkeys.png); +} + +#game .hud .key1 { + top : 8px; +} +#game .hud .key2 { + top : 40px; + background-position : -16px 0; +} + + +#game .hud .weapon { + position : absolute; + width : 96px; + height : 48px; + left : 512px; + top : 16px; + overflow : hidden; + background-image : url(art/hudweapons.png); +} + +#game .hud .number-container { + position : absolute; + height : 32px; + top : 32px; +} + +#game .hud .floor { + left : 48px; +} +#game .hud .score { + left : 96px; +} +#game .hud .lives { + left : 224px; +} +#game .hud .health { + left : 336px; +} +#game .hud .ammo { + left : 428px; +} + + +#game .hud .number { + display : inline-block; + width : 16px; + height : 32px; + overflow : hidden; + margin : 0; + background-image : url(art/hudnumbers.png); + background-repeat : no-repeat; +} + +#game .fps { + position : absolute; + display : none; + z-index : 1000; + left : 20px; + top : 15px; + font-family : courier new; + font-size : 16px; + width : 70px; + height : 16px; + background : rgba(0,0,0,0.3); + color : rgb(200,200,200); + padding : 5px; +} + + +#text-screen { + background-color : #8a0000; + position : absolute; + height : 100%; + width : 100%; + left : 0; + top : 0; + z-index : 500; + display : none; +} + +#game .intermission, +#game .gameover { + position : absolute; + height : 100%; + width : 100%; + left : 0; + top : 0; + background-color : #004141; + display : none; +} + +#game .gameover { + background-image : url(art/intermission_gameover.png); +} + +#game .intermission > div { + position : absolute; +} + +#game .intermission .background, +#game .intermission .background-secret, +#game .intermission .background-victory { + position : absolute; + background-image : url(art/intermission.png); + height : 100%; + width : 100%; + left : 0; + top : 0; + z-index : 0; + display : none; +} +#game .intermission .background-secret { + background-image : url(art/intermission_secret.png); +} +#game .intermission .background-victory { + background-image : url(art/intermission_victory.png); +} + +#game .intermission .bj { + left : 40px; + top : 32px; + width : 162px; + height : 174px; + background-image : url(art/intermissionbj.png); + overflow : hidden; + z-index : 10; +} + +#game .intermission .stat, +#game .intermission .victory-stat { + z-index : 10; +} + +#game .intermission .bonus { + left : 412px; + top : 108px; +} + +#game .intermission .floor { + left : 412px; + top : 32px; +} + + +#game .intermission .total-time-minutes { + top : 128px; + left : 224px; +} + +#game .intermission .total-time-seconds { + top : 128px; + left : 306px; +} + + +#game .intermission .time-minutes, +#game .intermission .par-minutes { + left : 412px; +} + +#game .intermission .time-seconds, +#game .intermission .par-seconds { + left : 498px; +} + +#game .intermission .time-minutes, +#game .intermission .time-seconds { + top : 152px; +} + +#game .intermission .par-minutes, +#game .intermission .par-seconds { + top : 184px; +} + +#game .intermission .kill-ratio, +#game .intermission .secret-ratio, +#game .intermission .treasure-ratio { + left : 492px; +} +#game .intermission .kill-ratio { + top : 224px; +} +#game .intermission .secret-ratio { + top : 256px; +} +#game .intermission .treasure-ratio { + top : 288px; +} + +#game .intermission .avg-kill-ratio, +#game .intermission .avg-secret-ratio, +#game .intermission .avg-treasure-ratio { + left : 384px; +} +#game .intermission .avg-kill-ratio { + top : 224px; +} +#game .intermission .avg-secret-ratio { + top : 256px; +} +#game .intermission .avg-treasure-ratio { + top : 288px; +} + +#game .intermission .digit { + display : inline-block; + width : 32px; + height : 32px; + background-image : url(art/intermissionfont.png); + background-repeat : no-repeat; + background-position : 32px 0px; +} +#game .intermission .num-0 { + background-position : 0px 0px; +} +#game .intermission .num-1 { + background-position : -32px 0px; +} +#game .intermission .num-2 { + background-position : -64px 0px; +} +#game .intermission .num-3 { + background-position : -96px 0px; +} +#game .intermission .num-4 { + background-position : -128px 0px; +} +#game .intermission .num-5 { + background-position : -160px 0px; +} +#game .intermission .num-6 { + background-position : -192px 0px; +} +#game .intermission .num-7 { + background-position : -224px 0px; +} +#game .intermission .num-8 { + background-position : -256px 0px; +} +#game .intermission .num-9 { + background-position : -288px 0px; +} + +#menu div.menu { + width : 100%; + height : 100%; +} + +#menu div.menu.main { + background-image : url(art/menubg_main.png); +} + +#menu div.menu.episodes { + background-image : url(art/menubg_episodes.png); +} + +#menu div.menu.levels { + background-image : url(art/menubg_levels.png); +} + +#menu div.menu.skill { + background-image : url(art/menubg_skill.png); +} + + +#menu div.menu.sound { + background-image : url(art/menubg_sound.png); +} + +#menu div.menu.control { + background-image : url(art/menubg_control.png); +} + +#menu div.menu.customize { + background-image : url(art/menubg_customize.png); +} + +#menu ul { + list-style : none; + margin : 0; + padding : 0; + position : absolute; +} + +#menu div.menu.main ul { + left : 196px; + top : 118px; + width : 330px; + height : 232px; +} + +#menu div.menu.sound ul { + left : 150px; + top : 87px; + width : 330px; + height : 232px; +} + +#menu div.menu.episodes ul { + left : 44px; + top : 100px; + width : 550px; + height : 240px; +} + +#menu div.menu.skill ul { + left : 144px; + top : 186px; + width : 384px; + height : 128px; +} + + +#menu div.menu.levels ul { + left : 90px; + top : 110px; + width : 256px; + height : 240px; +} + +#menu div.menu.control ul { + left : 160px; + top : 156px; + width : 350px; + height : 100px; +} + +#menu div.menu.customize ul { + left : 116px; + top : 192px; + width : 512px; + height : 96px; +} + + +#menu ul.two-column{ + position : relative; + float : left; + width : 256px; +} + +/* menu items */ + +#menu ul li div.button { + display : block; + height : 24px; + cursor : pointer; + margin-bottom : 8px; + background-image : url(art/menuitems.png); +} + +#menu li.newgame div.button { + background-position : 0 0; +} +#menu li.active.newgame div.button { + background-position : -384px 0; +} + +#menu li.sound div.button { + background-position : 0 -32px; +} +#menu li.active.sound div.button { + background-position : -384px -32px; +} + +#menu li.control div.button { + background-position : 0 -64px; +} +#menu li.active.control div.button { + background-position : -384px -64px; +} + +#menu li.readthis div.button { + background-position : 0 -96px; +} +#menu li.active.readthis div.button { + background-position : -384px -96px; +} + +#menu li.resumegame div.button { + background-position : 0 -128px; +} +#menu li.active.resumegame div.button { + background-position : -384px -128px; +} + +#menu li.baby div.button { + background-position : 0 -160px; +} +#menu li.active.baby div.button { + background-position : -384px -160px; +} + +#menu li.easy div.button { + background-position : 0 -192px; +} +#menu li.active.easy div.button { + background-position : -384px -192px; +} + +#menu li.medium div.button { + background-position : 0 -224px; +} +#menu li.active.medium div.button { + background-position : -384px -224px; +} + +#menu li.hard div.button { + background-position : 0 -256px; +} +#menu li.active.hard div.button { + background-position : -384px -256px; +} + +#menu li.sfxoff { + margin-bottom : 58px; +} + +#menu li.sfxon div.button, +#menu li.musicon div.button, +#menu li.sfxoff div.button, +#menu li.musicoff div.button { + margin-left : 48px; + width : 256px; +} + + +#menu li.sfxon div.button, +#menu li.musicon div.button { + background-position : 0 -288px; +} +#menu li.active.sfxon div.button, +#menu li.active.musicon div.button { + background-position : -384px -288px; +} + +#menu li.sfxoff div.button, +#menu li.musicoff div.button { + background-position : 0 -320px; +} +#menu li.active.sfxoff div.button, +#menu li.active.musicoff div.button { + background-position : -384px -320px; +} + +#menu li.mouseenabled div.button { + background-position : 0 -352px; +} +#menu li.active.mouseenabled div.button { + background-position : -384px -352px; +} +#menu li.customize div.button { + background-position : 0 -384px; +} +#menu li.active.customize div.button { + background-position : -384px -384px; +} + +#menu div.menu.episodes li div.button { + height : 56px; + width : 550px; + background-image : url(art/menuitems_episodes.png); +} + +#menu div.menu.episodes li.episode-0 div.button { + background-position : 0 0; +} +#menu div.menu.episodes li.active.episode-0 div.button { + background-position : 0 -56px; +} + +#menu div.menu.episodes li.episode-1 div.button { + background-position : 0 -112px; +} +#menu div.menu.episodes li.active.episode-1 div.button { + background-position : 0 -168px; +} + +#menu div.menu.episodes li.episode-2 div.button { + background-position : 0 -224px; +} +#menu div.menu.episodes li.active.episode-2 div.button { + background-position : 0 -280px; +} + + + +#menu div.menu.levels li div.button { + width : 256px; + margin-bottom : 16px; + background-image : url(art/menuitems_levels.png); +} + +#menu li.level-0 div.button { + background-position : 0 0; +} +#menu li.active.level-0 div.button { + background-position : -256px 0; +} + +#menu li.level-1 div.button { + background-position : 0 -32px; +} +#menu li.active.level-1 div.button { + background-position : -256px -32px; +} + +#menu li.level-2 div.button { + background-position : 0 -64px; +} +#menu li.active.level-2 div.button { + background-position : -256px -64px; +} + +#menu li.level-3 div.button { + background-position : 0 -96px; +} +#menu li.active.level-3 div.button { + background-position : -256px -96px; +} + +#menu li.level-4 div.button { + background-position : 0 -128px; +} +#menu li.active.level-4 div.button { + background-position : -256px -128px; +} + +#menu li.level-5 div.button { + background-position : 0 -160px; +} +#menu li.active.level-5 div.button { + background-position : -256px -160px; +} + +#menu li.level-6 div.button { + background-position : 0 -192px; +} +#menu li.active.level-6 div.button { + background-position : -256px -192px; +} + +#menu li.level-7 div.button { + background-position : 0 -224px; +} +#menu li.active.level-7 div.button { + background-position : -256px -224px; +} + +#menu li.level-8 div.button{ + background-position : 0 -256px; +} +#menu li.active.level-8 div.button { + background-position : -256px -256px; +} + +#menu li.level-9 div.button { + background-position : 0 -288px; +} +#menu li.active.level-9 div.button { + background-position : -256px -288px; +} + +/* menu toggle light */ + +#menu div.light { + width : 42px; + height : 16px; + margin-left : -48px; + margin-top : 4px; + overflow : hidden; + display : inline-block; + background-image : url(art/menulight.png); +} + +#menu div.light.on { + background-position : 0 24px; +} + +/* menu selector gun */ + +#menu ul.selector li.active::before { + display : block; + width : 46px; + height : 24px; + position : absolute; + left : -50px; + content : ""; + background-image : url(art/menuselector.png); +} + + +#menu div.menu.control ul.selector li.active::before { + left : -100px; +} + + +/* customize keys menu */ + +#menu div.menu.customize ul.selector li.active::before { + left : -96px; +} +#menu div.menu.customize li div.button { + margin-bottom : 28px; + background : none; +} + +#menu div.menu.customize li div.button span { + position : relative; + display : inline-block; + width : 122px; + height : 28px; + background-image : url(art/control_keys.png); + background-position : 0 -128px; + margin-right : -6px; +} +#menu div.menu.customize li div.button span.k1 { +} +#menu div.menu.customize li div.button span.k2 { +} +#menu div.menu.customize li div.button span.k3 { +} +#menu div.menu.customize li div.button span.k4 { +} + +#menu div.menu.customize li div.button span:hover { + +} + +/* skill menu face */ + +#menu div.menu.skill div.face { + width : 48px; + height : 64px; + left : 460px; + top : 210px; + position : absolute; + background-image : url(art/skillfaces.png); +} + +#menu div.menu.skill div.face.gd_baby { + background-position : 0 0; +} +#menu div.menu.skill div.face.gd_easy { + background-position : -48px 0; +} +#menu div.menu.skill div.face.gd_medium { + background-position : -96px 0; +} +#menu div.menu.skill div.face.gd_hard { + background-position : -144px 0; +} + + +/* menu confirm box */ + +#menu .message { + position : absolute; + z-index : 1000; + left : 0; + top : 0; + width : 100%; + height : 100%; + display : none; +} + +#menu .message.confirm-newgame div.box { + position : absolute; + width : 460px; + height : 100px; + left : 50%; + top : 50%; + margin-left : -230px; + margin-top : -50px; + overflow : hidden; + background-image : url(art/confirm_newgame.png); +} + +#menu .message.confirm-newgame div.box.blink { + background-position : 0 100px; +} + diff --git a/wolf3d.html b/wolf3d.html new file mode 100644 index 0000000..36e8597 --- /dev/null +++ b/wolf3d.html @@ -0,0 +1,232 @@ + + + + + + + + + + + + Wolfenstein 3D + + + + + + + + + +
+
+ + + +
+ + +
+
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file