mirror of
https://github.com/id-Software/wolf3d-browser.git
synced 2024-11-21 12:11:13 +00:00
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
This commit is contained in:
commit
e0b653888d
32 changed files with 14155 additions and 0 deletions
345
COPYING.txt
Normal file
345
COPYING.txt
Normal file
|
@ -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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
22
README.txt
Normal file
22
README.txt
Normal file
|
@ -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.
|
||||
|
64
index.html
Normal file
64
index.html
Normal file
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<!--
|
||||
Copyright (C) 2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the WOLF3D Browser Version GPL Source Code.
|
||||
-->
|
||||
<meta charset="UTF-8">
|
||||
<title>Test Page</title>
|
||||
<style>
|
||||
body {
|
||||
background-color : black;
|
||||
text-align : center;
|
||||
}
|
||||
#wolf3d {
|
||||
margin-top : 100px;
|
||||
border : none;
|
||||
width : 640px;
|
||||
height : 400px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe id="wolf3d" src="wolf3d.html" mozallowfullscreen="true" webkitallowfullscreen="true">
|
||||
</iframe>
|
||||
|
||||
|
||||
<script>
|
||||
window.onfocus = function() {
|
||||
var game = window.frames[0];
|
||||
if (game) {
|
||||
game.focus();
|
||||
}
|
||||
};
|
||||
window.oncontextmenu = function(e) {
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
var game = window.frames[0];
|
||||
if (game && game.Wolf && game.Wolf.Input) {
|
||||
if (game.Wolf.Input.rightMouseDown()) {
|
||||
game.Wolf.Input.resetMouse();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
window.onmouseup = function(e) {
|
||||
var game = window.frames[0];
|
||||
if (game && game.Wolf && game.Wolf.Input) {
|
||||
if (game.Wolf.Input.rightMouseDown() || game.Wolf.Input.leftMouseDown()) {
|
||||
game.Wolf.Input.resetMouse();
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
562
js/actorai.js
Normal file
562
js/actorai.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<level.state.numGuards;++n) {
|
||||
if (level.state.guards[n].state >= 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
|
||||
};
|
||||
|
||||
})();
|
518
js/actors.js
Normal file
518
js/actors.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
};
|
||||
|
||||
})();
|
1631
js/actstat.js
Normal file
1631
js/actstat.js
Normal file
File diff suppressed because it is too large
Load diff
143
js/angle.js
Normal file
143
js/angle.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
}
|
||||
|
||||
})();
|
149
js/areas.js
Normal file
149
js/areas.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;i++) {
|
||||
level.state.areaconnect[i] = [];
|
||||
for (var j=0;j<Wolf.NUMAREAS;j++) {
|
||||
level.state.areaconnect[i][j] = 0;
|
||||
}
|
||||
level.state.areabyplayer[i] = false;
|
||||
}
|
||||
level.state.areabyplayer[areanumber] = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @description Scans outward from playerarea, marking all connected areas.
|
||||
* @param {object} level The level object
|
||||
* @param {number} areanumber Area
|
||||
*/
|
||||
function recursiveConnect(level, areanumber) {
|
||||
for (var i = 0;i < Wolf.NUMAREAS; ++i) {
|
||||
if (level.state.areaconnect[areanumber][i] && !level.state.areabyplayer[i]) {
|
||||
level.state.areabyplayer[i] = true;
|
||||
recursiveConnect(level, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Connect area.
|
||||
* @memberOf Wolf.Areas
|
||||
* @param {object} level The level object
|
||||
* @param {number} areanumber New area
|
||||
*/
|
||||
function connect(level, areanumber) {
|
||||
var i, c = 0;
|
||||
|
||||
if (areanumber >= 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
|
||||
};
|
||||
|
||||
})();
|
||||
|
422
js/doors.js
Normal file
422
js/doors.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <DOOR_FULLOPEN if partially opened.
|
||||
*/
|
||||
function opened(door) {
|
||||
return door.action == Wolf.dr_open ? Wolf.DOOR_FULLOPEN : door.ticcount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Process door actions.
|
||||
* @memberOf Wolf.Doors
|
||||
* @param {object} level The level object
|
||||
* @param {object} player The player object
|
||||
* @param {number} tics Tics since last
|
||||
*/
|
||||
function process(level, player, tics) {
|
||||
if (player.playstate == Wolf.ex_victory) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var n=0;n<level.state.numDoors;++n) {
|
||||
var door = level.state.doors[n],
|
||||
doorPos = {
|
||||
x : Wolf.TILE2POS(door.tile.x),
|
||||
y : Wolf.TILE2POS(door.tile.y)
|
||||
};
|
||||
switch (door.action) {
|
||||
case Wolf.dr_closed: // this door is closed!
|
||||
continue;
|
||||
|
||||
case Wolf.dr_opening:
|
||||
if (door.ticcount >= 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<level.state.numDoors ; ++n){
|
||||
door = level.state.doors[n];
|
||||
x = door.tile.x;
|
||||
y = door.tile.y;
|
||||
|
||||
if (door.vertical) {
|
||||
door.area1 = level.areas[x + 1][y] >= 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<level.state.numGuards;++n) {
|
||||
guard = level.state.guards[n];
|
||||
if (guard.tile.x == x && guard.tile.y == y ) {
|
||||
return false; // guard in door
|
||||
}
|
||||
if (guard.tile.x == x - 1 && guard.tile.y == y && Wolf.POS2TILE(guard.x + Wolf.CLOSEWALL) == x) {
|
||||
return false; // guard in door
|
||||
}
|
||||
if (guard.tile.x == x + 1 && guard.tile.y == y && Wolf.POS2TILE(guard.x - Wolf.CLOSEWALL) == x) {
|
||||
return false; // guard in door
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tileX == x) {
|
||||
if (Wolf.POS2TILE(player.position.y + Wolf.CLOSEWALL) == y) {
|
||||
return false;
|
||||
}
|
||||
if (Wolf.POS2TILE(player.position.y - Wolf.CLOSEWALL) == y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (n = 0; n<level.state.numGuards;++n) {
|
||||
var guard = level.state.guards[n];
|
||||
if (guard.tile.x == x && guard.tile.y == y ) {
|
||||
return false; // guard in door
|
||||
}
|
||||
if (guard.tile.x == x && guard.tile.y == y - 1 && Wolf.POS2TILE(guard.y + Wolf.CLOSEWALL) == y) {
|
||||
return false; // guard in door
|
||||
}
|
||||
if (guard.tile.x == x && guard.tile.y == y + 1 && Wolf.POS2TILE(guard.y - Wolf.CLOSEWALL) == y) {
|
||||
return false; // guard in door
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Try to use a door with keys that the player has.
|
||||
* @memberOf Wolf.Doors
|
||||
* @param {object} level The level object
|
||||
* @param {object} player The player object
|
||||
* @param {object} door The door object
|
||||
* @returns {boolean} Always returns true.
|
||||
*/
|
||||
function tryUse(level, player, door ) {
|
||||
switch (door.type) {
|
||||
case Wolf.DOOR_VERT:
|
||||
case Wolf.DOOR_HORIZ:
|
||||
case Wolf.DOOR_E_VERT:
|
||||
case Wolf.DOOR_E_HORIZ:
|
||||
changeDoorState(level, player, door); // does not require key!
|
||||
break;
|
||||
|
||||
case Wolf.DOOR_G_VERT:
|
||||
case Wolf.DOOR_G_HORIZ:
|
||||
if (player.items & Wolf.ITEM_KEY_1) {
|
||||
changeDoorState(level, player, door);
|
||||
} else {
|
||||
Wolf.Game.notify("You need a gold key");
|
||||
}
|
||||
break;
|
||||
|
||||
case Wolf.DOOR_S_VERT:
|
||||
case Wolf.DOOR_S_HORIZ:
|
||||
if (player.items & Wolf.ITEM_KEY_2) {
|
||||
changeDoorState(level, player, door);
|
||||
} else {
|
||||
Wolf.Game.notify("You need a silver key");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true; // FIXME
|
||||
}
|
||||
|
||||
return {
|
||||
reset : reset,
|
||||
spawn : spawn,
|
||||
opened : opened,
|
||||
open : open,
|
||||
tryUse : tryUse,
|
||||
process : process,
|
||||
setAreas : setAreas
|
||||
};
|
||||
|
||||
})();
|
80
js/episodes.js
Normal file
80
js/episodes.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* ===========================================================================
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
217
js/file.js
Normal file
217
js/file.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<len;) {
|
||||
b1 = b64chars.indexOf(str.charAt(i++));
|
||||
b2 = b64chars.indexOf(str.charAt(i++));
|
||||
b3 = b64chars.indexOf(str.charAt(i++));
|
||||
b4 = b64chars.indexOf(str.charAt(i++));
|
||||
|
||||
a = ((b1 & 0x3F) << 2) | ((b2 >> 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<num;i++) {
|
||||
b[i] = f.data.charCodeAt(f.position+i) & 0xFF;
|
||||
}
|
||||
f.position += num;
|
||||
return b;
|
||||
}
|
||||
|
||||
return {
|
||||
open : open,
|
||||
readInt8 : readInt8,
|
||||
readUInt8 : readUInt8,
|
||||
readInt16 : readInt16,
|
||||
readUInt16 : readUInt16,
|
||||
readInt32 : readInt32,
|
||||
readUInt32 : readUInt32,
|
||||
readBytes : readBytes,
|
||||
readString : readString
|
||||
};
|
||||
|
||||
})();
|
1351
js/game.js
Normal file
1351
js/game.js
Normal file
File diff suppressed because it is too large
Load diff
359
js/input.js
Normal file
359
js/input.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<n;i++) {
|
||||
bindings[e.keyCode][i](e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.on("keyup", function(e) {
|
||||
e.preventDefault();
|
||||
if (!Wolf.Game.isPlaying()) {
|
||||
return;
|
||||
}
|
||||
keys[e.keyCode] = false;
|
||||
})
|
||||
.on("keypress", function(e) {
|
||||
e.preventDefault();
|
||||
})
|
||||
.on("contextmenu", function(e) {
|
||||
e.preventDefault();
|
||||
})
|
||||
.on("onrightclick", function(e) {
|
||||
e.preventDefault();
|
||||
})
|
||||
.on("mousedown", function(e) {
|
||||
window.focus();
|
||||
e.preventDefault();
|
||||
})
|
||||
.on("mouseup", function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$("#game")
|
||||
.on("mousedown", function(e) {
|
||||
if (hasFocus) {
|
||||
if (e.which == 1) {
|
||||
lmbDown = true;
|
||||
} else if (e.which == 3) {
|
||||
rmbDown = true;
|
||||
}
|
||||
} else {
|
||||
window.focus();
|
||||
}
|
||||
e.preventDefault();
|
||||
})
|
||||
.on("mouseup", function(e) {
|
||||
if (hasFocus) {
|
||||
if (e.which == 1) {
|
||||
lmbDown = false;
|
||||
} else if (e.which == 3) {
|
||||
rmbDown = false;
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
})
|
||||
.on("mousemove", function(e) {
|
||||
if (!hasFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPointerLocked()) {
|
||||
if ("webkitMovementX" in e.originalEvent) {
|
||||
mouseMoveX += e.originalEvent.webkitMovementX;
|
||||
mouseMoveY += e.originalEvent.webkitMovementY;
|
||||
} else if ("mozMovementX" in e.originalEvent) {
|
||||
mouseMoveX += e.originalEvent.mozMovementX;
|
||||
mouseMoveY += e.originalEvent.mozMovementY;
|
||||
} else if ("movementX" in e.originalEvent) {
|
||||
mouseMoveX += e.originalEvent.movementX;
|
||||
mouseMoveY += e.originalEvent.movementY;
|
||||
}
|
||||
} else {
|
||||
if (Wolf.Game.isFullscreen()) {
|
||||
mouseX = e.pageX / window.innerWidth;
|
||||
mouseY = e.pageY / window.innerHeight;
|
||||
} else {
|
||||
var offset = main.offset();
|
||||
mouseX = (e.pageX - offset.left) / main.width();
|
||||
mouseY = (e.pageY - offset.top) / main.height();
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
// reset keys and mouse if window/tab loses focus
|
||||
$(window).on("blur", function(e) {
|
||||
hasFocus = false;
|
||||
reset();
|
||||
});
|
||||
$(window).on("focus", function(e) {
|
||||
hasFocus = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
resetMouse();
|
||||
keys = [];
|
||||
}
|
||||
|
||||
function resetMouse() {
|
||||
lmbDown = false;
|
||||
rmbDown = false;
|
||||
mouseX = mouseY = 0.5;
|
||||
}
|
||||
|
||||
function bindKey(k, handler) {
|
||||
var keyCode = Wolf.Keys[k];
|
||||
if (!bindings[keyCode]) {
|
||||
bindings[keyCode] = [];
|
||||
}
|
||||
bindings[keyCode].push(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberOf Wolf.Input
|
||||
* @description Check if one of the specified keys is pressed.
|
||||
* @param {array} keys Array of key names.
|
||||
* @returns {boolean} True if a key is pressed, otherwise false.
|
||||
*/
|
||||
function checkKeys(ckeys) {
|
||||
for (var i=0;i<ckeys.length;i++) {
|
||||
var k = ckeys[i];
|
||||
if (!!keys[Wolf.Keys[k]]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberOf Wolf.Input
|
||||
* @description Clear status for keys.
|
||||
* @param {array} keys Array of key names.
|
||||
*/
|
||||
function clearKeys(ckeys) {
|
||||
for (var i=0;i<ckeys.length;i++) {
|
||||
var k = ckeys[i];
|
||||
keys[Wolf.Keys[k]] = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function leftMouseDown() {
|
||||
return lmbDown;
|
||||
}
|
||||
|
||||
function rightMouseDown() {
|
||||
return rmbDown;
|
||||
}
|
||||
|
||||
function getMouseCoords() {
|
||||
if (mouseX < 0 || mouseX > 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
|
||||
};
|
1134
js/level.js
Normal file
1134
js/level.js
Normal file
File diff suppressed because it is too large
Load diff
126
js/load.js
Normal file
126
js/load.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 = $("<div>"),
|
||||
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);
|
37
js/maps.sample.js
Normal file
37
js/maps.sample.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 ..."
|
||||
};
|
329
js/math.js
Normal file
329
js/math.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
};
|
||||
|
||||
})();
|
622
js/menu.js
Normal file
622
js/menu.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<keySpriteNames.length;i++) {
|
||||
if (keySpriteNames[i] !== "") {
|
||||
keySprites[keySpriteNames[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
function playSound(file) {
|
||||
Wolf.Sound.startSound(null, null, 1, Wolf.CHAN_AUTO, file, 1, Wolf.ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
function setActiveItem(item) {
|
||||
playSound("lsfx/005.wav");
|
||||
|
||||
$("#menu div.menu.active li").removeClass("active");
|
||||
item.addClass("active");
|
||||
|
||||
if ($("#menu div.menu.active").hasClass("skill")) {
|
||||
$("#menu div.menu.active div.face")
|
||||
.removeClass()
|
||||
.addClass("face " + item.data("skill"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Bind events to menu items
|
||||
* @private
|
||||
*/
|
||||
function setupEvents() {
|
||||
$(document).on("keydown", function(e) {
|
||||
|
||||
if (!$("#menu").is(":visible")) {
|
||||
return;
|
||||
}
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oldActive = activeIndex;
|
||||
switch (e.keyCode) {
|
||||
case 38:
|
||||
activeIndex--;
|
||||
activeMouseItem = null;
|
||||
break;
|
||||
case 40:
|
||||
activeIndex++;
|
||||
activeMouseItem = null;
|
||||
break;
|
||||
case 13:
|
||||
if (activeMouseItem) {
|
||||
activeMouseItem.trigger("click");
|
||||
} else {
|
||||
$("#menu div.menu.active li").eq(activeIndex).trigger("click");
|
||||
}
|
||||
break;
|
||||
case 27: // ESC
|
||||
var back = $("#menu div.menu.active").data("backmenu");
|
||||
if (back) {
|
||||
playSound("lsfx/039.wav");
|
||||
show(back);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (oldActive != activeIndex) {
|
||||
var items = $("#menu div.menu.active li:not(.hidden)");
|
||||
if (activeIndex < 0) {
|
||||
activeIndex += items.length;
|
||||
}
|
||||
activeIndex %= items.length;
|
||||
setActiveItem(items.eq(activeIndex));
|
||||
}
|
||||
});
|
||||
|
||||
$("#menu li").mouseover(function() {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
activeMouseItem = $(this);
|
||||
setActiveItem($(this));
|
||||
});
|
||||
|
||||
$("#menu li").on("click", function(e) {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
playSound("lsfx/032.wav");
|
||||
|
||||
var $this = $(this),
|
||||
sub = $this.data("submenu");
|
||||
if (sub) {
|
||||
show(sub);
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if ($this.hasClass("sfxon")) {
|
||||
$("div.light", $this).addClass("on");
|
||||
$("#menu li.sfxoff div.light").removeClass("on");
|
||||
Wolf.Sound.toggleSound(true);
|
||||
}
|
||||
if ($this.hasClass("sfxoff")) {
|
||||
$("div.light", $this).addClass("on");
|
||||
$("#menu li.sfxon div.light").removeClass("on");
|
||||
Wolf.Sound.toggleSound(false);
|
||||
}
|
||||
if ($this.hasClass("musicon")) {
|
||||
$("div.light", $this).addClass("on");
|
||||
$("#menu li.musicoff div.light").removeClass("on");
|
||||
Wolf.Sound.toggleMusic(true);
|
||||
}
|
||||
if ($this.hasClass("musicoff")) {
|
||||
$("div.light", $this).addClass("on");
|
||||
$("#menu li.musicon div.light").removeClass("on");
|
||||
Wolf.Sound.toggleMusic(false);
|
||||
}
|
||||
if ($this.hasClass("mouseenabled")) {
|
||||
var mouseOn = Wolf.Game.isMouseEnabled();
|
||||
$("div.light", $this).toggleClass("on", !mouseOn);
|
||||
Wolf.Game.enableMouse(!mouseOn);
|
||||
}
|
||||
|
||||
if ($this.hasClass("customizekeys")) {
|
||||
customizeKeys($this);
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$("#menu div.menu.episodes li").on("click", function(e) {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
var episode = $(this).data("episode");
|
||||
if (Wolf.Game.isPlaying()) {
|
||||
showMessage("confirm-newgame", true, function(result) {
|
||||
if (result) {
|
||||
activeEpisode = episode;
|
||||
show("skill");
|
||||
} else {
|
||||
show("main");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
activeEpisode = episode;
|
||||
show("skill");
|
||||
}
|
||||
});
|
||||
|
||||
$("#menu div.menu.skill li").on("click", function(e) {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
activeSkill = $(this).data("skill");
|
||||
});
|
||||
|
||||
$("#menu div.menu.main li.resumegame").on("click", function(e) {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
if (Wolf.Game.isPlaying()) {
|
||||
hide();
|
||||
Wolf.Game.resume();
|
||||
}
|
||||
});
|
||||
|
||||
$("#menu div.menu.main li.readthis").on("click", function(e) {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
menuInputActive = false;
|
||||
$("#menu").fadeOut(null, function() {
|
||||
showText("help", 11, function() {
|
||||
$("#menu").fadeIn();
|
||||
});
|
||||
});
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$("#menu div.menu.levels li").on("click", function(e) {
|
||||
if (!menuInputActive) {
|
||||
return;
|
||||
}
|
||||
var level, gameState;
|
||||
|
||||
hide();
|
||||
level = $(this).data("level");
|
||||
|
||||
gameState = Wolf.Game.startGame(Wolf[activeSkill]);
|
||||
Wolf.Game.startLevel(gameState, activeEpisode, level);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function customizeKeys($this) {
|
||||
menuInputActive = false;
|
||||
|
||||
var current = 0,
|
||||
isBinding = false,
|
||||
blinkInterval;
|
||||
|
||||
function selectKey(index) {
|
||||
if (index < 0) index += 4;
|
||||
index = index % 4;
|
||||
var currentSprite = $("span.active", $this);
|
||||
if (currentSprite[0]) {
|
||||
setCustomizeKey(
|
||||
currentSprite.data("action"),
|
||||
currentSprite.data("keyIndex"),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
var sprite = $("span.k" + (index+1), $this);
|
||||
setCustomizeKey(
|
||||
sprite.data("action"),
|
||||
sprite.data("keyIndex"),
|
||||
true
|
||||
);
|
||||
current = index;
|
||||
}
|
||||
|
||||
function activateKey(index) {
|
||||
isBinding = true;
|
||||
|
||||
var sprite = $("span.k" + (index+1), $this),
|
||||
blink = false;
|
||||
|
||||
setCustomizeKey(
|
||||
sprite.data("action"), "QUESTION", true
|
||||
);
|
||||
|
||||
if (blinkInterval) {
|
||||
clearInterval(blinkInterval);
|
||||
}
|
||||
blinkInterval = setInterval(function() {
|
||||
setCustomizeKey(sprite.data("action"), (blink = !blink) ? "BLANK" : "QUESTION", true);
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function bindKey(index, key) {
|
||||
var sprite = $("span.k" + (index+1), $this);
|
||||
setCustomizeKey(
|
||||
sprite.data("action"),
|
||||
key,
|
||||
true
|
||||
);
|
||||
Wolf.Game.bindControl(sprite.data("action"), [key]);
|
||||
}
|
||||
|
||||
function exitCustomize() {
|
||||
$(document).off("keydown", keyHandler);
|
||||
initCustomizeMenu();
|
||||
menuInputActive = true;
|
||||
}
|
||||
|
||||
function keyHandler(e) {
|
||||
var i;
|
||||
if (isBinding) {
|
||||
// look for key in bindable key codes. TODO: LUT?
|
||||
for (i=2;i<keySpriteNames.length;i++) {
|
||||
if (Wolf.Keys[keySpriteNames[i]] == e.keyCode) {
|
||||
bindKey(current, keySpriteNames[i]);
|
||||
isBinding = false;
|
||||
clearInterval(blinkInterval);
|
||||
blinkInterval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.keyCode) {
|
||||
case 39: // right
|
||||
selectKey(current + 1);
|
||||
break;
|
||||
case 37: // left
|
||||
selectKey(current - 1);
|
||||
break;
|
||||
case 13: // enter
|
||||
activateKey(current);
|
||||
break;
|
||||
case 27: // ESC
|
||||
case 38: // up
|
||||
case 40: // down
|
||||
exitCustomize()
|
||||
break;
|
||||
}
|
||||
}
|
||||
$(document).on("keydown", keyHandler);
|
||||
|
||||
|
||||
selectKey(current);
|
||||
}
|
||||
|
||||
function setCustomizeKey(action, keyIndex, active) {
|
||||
var menu = $("#menu div.menu.customize"),
|
||||
x = (active ? -256 : 0),
|
||||
y = -keySprites[keyIndex] * 32;
|
||||
$("span." + action, menu)
|
||||
.css(
|
||||
"backgroundPosition", x + "px " + y + "px"
|
||||
)
|
||||
.data("keyIndex", keyIndex)
|
||||
.toggleClass("active", !!active);
|
||||
}
|
||||
|
||||
function initCustomizeMenu() {
|
||||
var controls = Wolf.Game.getControls(),
|
||||
keys = ["run", "use", "attack", "strafe", "left", "right", "up", "down"],
|
||||
i;
|
||||
|
||||
for (i=0;i<keys.length;i++) {
|
||||
setCustomizeKey(keys[i], controls[keys[i]][0])
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(name, blink, onclose) {
|
||||
var box,
|
||||
blinkOn = false;
|
||||
|
||||
activeMessage = name;
|
||||
menuInputActive = false;
|
||||
|
||||
if (messageBlink) {
|
||||
clearInterval(messageBlink);
|
||||
messageBlink = 0;
|
||||
}
|
||||
|
||||
$("#menu .message." + name).show();
|
||||
|
||||
box = $("#menu .message." + name + " div.box");
|
||||
|
||||
box.removeClass("blink");
|
||||
|
||||
if (blink) {
|
||||
setInterval(function() {
|
||||
blinkOn = !blinkOn;
|
||||
if (blinkOn) {
|
||||
box.addClass("blink");
|
||||
} else {
|
||||
box.removeClass("blink");
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function close(value) {
|
||||
playSound("lsfx/039.wav");
|
||||
$(document).off("keydown", keyHandler);
|
||||
$("#menu .message." + name).hide();
|
||||
if (messageBlink) {
|
||||
clearInterval(messageBlink);
|
||||
messageBlink = 0;
|
||||
}
|
||||
menuInputActive = true;
|
||||
|
||||
if (onclose) {
|
||||
onclose(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function keyHandler(e) {
|
||||
switch (e.keyCode) {
|
||||
case 27: // ESC
|
||||
case 78: // N
|
||||
close(false);
|
||||
break;
|
||||
case 89: // Y
|
||||
close(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on("keydown", keyHandler);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description Show the menu
|
||||
* @memberOf Wolf.Menu
|
||||
*/
|
||||
function show(menuName) {
|
||||
var musicOn, soundOn, mouseOn;
|
||||
|
||||
if (!setupDone) {
|
||||
setupEvents();
|
||||
setupDone = true;
|
||||
}
|
||||
Wolf.Sound.startMusic("music/WONDERIN.ogg");
|
||||
|
||||
menuName = menuName || "main";
|
||||
|
||||
if (menuName == "main") {
|
||||
if (Wolf.Game.isPlaying()) {
|
||||
$("#menu div.menu.main li.resumegame")
|
||||
.removeClass("hidden")
|
||||
.show();
|
||||
} else {
|
||||
$("#menu div.menu.main li.resumegame")
|
||||
.addClass("hidden")
|
||||
.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (menuName == "customize") {
|
||||
initCustomizeMenu();
|
||||
}
|
||||
|
||||
if (menuName == "episodes") {
|
||||
$("#menu div.menu.episodes li")
|
||||
.removeClass("hidden")
|
||||
.show();
|
||||
|
||||
if (!Wolf.Episodes[0].enabled) {
|
||||
$("#menu div.menu.episodes li.episode-0")
|
||||
.addClass("hidden")
|
||||
.hide();
|
||||
}
|
||||
if (!Wolf.Episodes[1].enabled) {
|
||||
$("#menu div.menu.episodes li.episode-1")
|
||||
.addClass("hidden")
|
||||
.hide();
|
||||
}
|
||||
if (!Wolf.Episodes[2].enabled) {
|
||||
$("#menu div.menu.episodes li.episode-2")
|
||||
.addClass("hidden")
|
||||
.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (menuName == "sound") {
|
||||
musicOn = Wolf.Sound.isMusicEnabled();
|
||||
soundOn = Wolf.Sound.isSoundEnabled();
|
||||
$("#menu li.sfxoff div.light").toggleClass("on", !soundOn);
|
||||
$("#menu li.sfxon div.light").toggleClass("on", soundOn);
|
||||
$("#menu li.musicoff div.light").toggleClass("on", !musicOn);
|
||||
$("#menu li.musicon div.light").toggleClass("on", musicOn);
|
||||
}
|
||||
|
||||
if (menuName == "control") {
|
||||
mouseOn = Wolf.Game.isMouseEnabled();
|
||||
$("#menu li.mouseenabled div.light").toggleClass("on", mouseOn);
|
||||
}
|
||||
|
||||
if ($("#menu").data("menu")) {
|
||||
$("#menu").removeClass($("#menu").data("menu"));
|
||||
}
|
||||
$("#menu div.menu").removeClass("active").hide();
|
||||
$("#menu li").removeClass("active");
|
||||
$("#menu").data("menu", menuName).addClass(menuName).show();
|
||||
$("#menu div.menu." + menuName).addClass("active").show();
|
||||
$("#menu div.menu." + menuName + " ul li").first().addClass("active");
|
||||
$("#menu").focus();
|
||||
|
||||
activeIndex = 0;
|
||||
activeMouseItem = null;
|
||||
menuInputActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Hide the menu
|
||||
* @memberOf Wolf.Menu
|
||||
*/
|
||||
function hide() {
|
||||
$("#menu").hide();
|
||||
menuInputActive = false;
|
||||
}
|
||||
|
||||
function showText(name, num, closeFunction) {
|
||||
var screen = $("#text-screen"),
|
||||
current = 0;
|
||||
|
||||
menuInputActive = false;
|
||||
|
||||
function show(moveIdx) {
|
||||
current += moveIdx;
|
||||
if (current < 0) {
|
||||
current += num;
|
||||
}
|
||||
current = current % num;
|
||||
screen.css({
|
||||
"backgroundImage" : "url(art/text-screens/" + name + "-" + (current+1) + ".png)"
|
||||
});
|
||||
// preload the next in the background
|
||||
var next = (current + 1) % num,
|
||||
nextImg = new Image();
|
||||
nextImg.src = "art/text-screens/" + name + "-" + (next+1) + ".png";
|
||||
}
|
||||
function close() {
|
||||
$(document).off("keydown", keyHandler);
|
||||
screen.fadeOut(null, closeFunction);
|
||||
menuInputActive = true;
|
||||
}
|
||||
|
||||
function keyHandler(e) {
|
||||
switch (e.keyCode) {
|
||||
case 39: // right
|
||||
show(1);
|
||||
break;
|
||||
case 37: // left
|
||||
show(-1);
|
||||
break;
|
||||
case 27: // ESC
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
show(0);
|
||||
|
||||
screen.fadeIn(null, function() {
|
||||
$(document).on("keydown", keyHandler);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show : show,
|
||||
hide : hide,
|
||||
showText : showText
|
||||
};
|
||||
|
||||
})();
|
814
js/player.js
Normal file
814
js/player.js
Normal file
|
@ -0,0 +1,814 @@
|
|||
/*
|
||||
* ===========================================================================
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
};
|
||||
|
||||
})();
|
309
js/powerups.js
Normal file
309
js/powerups.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <!only!> 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<level.state.numPowerups; i++) {
|
||||
pow = level.state.powerups[i];
|
||||
if (pow.x == x && pow.y == y) {
|
||||
// got a powerup here
|
||||
if (give(level, player, pow.type)) { //FIXME script
|
||||
// picked up this stuff, remove it!
|
||||
p_pick = true;
|
||||
Wolf.Sprites.remove(level, pow.sprite);
|
||||
remove(level, pow);
|
||||
} else {
|
||||
// player do not need it, so may be next time!
|
||||
p_left = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(p_left) {
|
||||
level.tileMap[x][y] |= Wolf.POWERUP_TILE;
|
||||
} else {
|
||||
level.tileMap[x][y] &= ~Wolf.POWERUP_TILE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
spawn : spawn,
|
||||
reset : reset,
|
||||
pickUp : pickUp
|
||||
};
|
||||
|
||||
})();
|
145
js/pushwall.js
Normal file
145
js/pushwall.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* ===========================================================================
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
};
|
||||
|
||||
})();
|
74
js/random.js
Normal file
74
js/random.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
}
|
||||
|
||||
})();
|
302
js/raycaster.js
Normal file
302
js/raycaster.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
};
|
||||
|
||||
})();
|
434
js/renderer.js
Normal file
434
js/renderer.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<Wolf.XRES; x += Wolf.SLICE_WIDTH) {
|
||||
slice = $("<div>");
|
||||
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 ? $("<div>") : $("<img>");
|
||||
|
||||
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<visibleSprites.length;n++) {
|
||||
sprite = visibleSprites[n].sprite;
|
||||
if (sprite && sprite.div) {
|
||||
sprite.div.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function draw(viewport, level, tracers, visibleTiles) {
|
||||
var n, tracePoint;
|
||||
|
||||
for (var n=0,len=tracers.length;n<len;++n) {
|
||||
tracePoint = tracers[n];
|
||||
if (!tracePoint.oob) {
|
||||
if (tracePoint.flags & Wolf.TRACE_HIT_DOOR) {
|
||||
drawDoor(n, viewport, tracePoint, level);
|
||||
} else {
|
||||
drawWall(n, viewport, tracePoint, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
drawSprites(viewport, level, visibleTiles);
|
||||
}
|
||||
|
||||
function updateSlice(n, textureSrc, proc) {
|
||||
var slice = slices[n],
|
||||
image = slice.texture,
|
||||
sliceStyle = slice.style,
|
||||
imgStyle = image.style,
|
||||
top = (Wolf.YRES - proc.h) / 2,
|
||||
left = -(proc.offset) >> 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 ? $("<div>") : $("<img>");
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
})();
|
56
js/requestanimframe.js
Normal file
56
js/requestanimframe.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
})();
|
||||
|
||||
})();
|
||||
|
208
js/sound.js
Normal file
208
js/sound.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<exts.length;i++) {
|
||||
if (Modernizr.audio[exts[i]] == "probably") {
|
||||
ext = exts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// look for a maybe
|
||||
if (!ext) {
|
||||
for (var i=0;i<exts.length;i++) {
|
||||
if (Modernizr.audio[exts[i]] == "maybe") {
|
||||
ext = exts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return file.split(".")[0] + "." + ext
|
||||
}
|
||||
|
||||
function createAudioElement() {
|
||||
var audio = new Audio();
|
||||
audioElements.push(audio);
|
||||
return audio;
|
||||
}
|
||||
|
||||
function startSound(posPlayer, posSound, entNum, entChannel, file, volume, attenuation, timeOfs) {
|
||||
var audio, dx, dy, dist;
|
||||
|
||||
if (!sounds[file]) {
|
||||
sounds[file] = [];
|
||||
}
|
||||
for (var i=0;i<sounds[file].length;i++) {
|
||||
if (sounds[file][i].ended || sounds[file][i].paused) {
|
||||
audio = sounds[file][i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!audio) {
|
||||
audio = createAudioElement();
|
||||
audio.src = getFileName(file);
|
||||
sounds[file].push(audio);
|
||||
}
|
||||
|
||||
if (posPlayer && posSound) {
|
||||
dx = (posPlayer.x - posSound.x) / Wolf.TILEGLOBAL;
|
||||
dy = (posPlayer.y - posSound.y) / Wolf.TILEGLOBAL;
|
||||
dist = dx * dx + dy * dy;
|
||||
volume *= 1 / (1 + dist / 50);
|
||||
}
|
||||
|
||||
audio.volume = volume * Wolf.MASTER_VOLUME * (soundEnabled ? 1 : 0);
|
||||
audio.play();
|
||||
}
|
||||
|
||||
function startMusic(file) {
|
||||
if (!music) {
|
||||
music = createAudioElement();
|
||||
music.loop = true;
|
||||
}
|
||||
var filename = getFileName(file);
|
||||
if (currentMusic != filename) {
|
||||
music.src = currentMusic = filename;
|
||||
music.volume = Wolf.MUSIC_VOLUME * Wolf.MASTER_VOLUME * (musicEnabled ? 1 : 0);
|
||||
music.play();
|
||||
}
|
||||
}
|
||||
|
||||
function stopAllSounds() {
|
||||
for (var i=0;i<audioElements.length;i++) {
|
||||
if (audioElements[i].currentTime > 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
|
||||
}
|
||||
}
|
||||
})();
|
1085
js/sprites.js
Normal file
1085
js/sprites.js
Normal file
File diff suppressed because it is too large
Load diff
175
js/weapon.js
Normal file
175
js/weapon.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<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 || 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
|
||||
};
|
||||
|
||||
|
||||
})();
|
117
js/wolf.js
Normal file
117
js/wolf.js
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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)+Wolf.HALFTILE); },
|
||||
POS2TILE : 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);
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
887
styles.css
Normal file
887
styles.css
Normal file
|
@ -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;
|
||||
}
|
||||
|
232
wolf3d.html
Normal file
232
wolf3d.html
Normal file
|
@ -0,0 +1,232 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<!--
|
||||
Copyright (C) 2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the WOLF3D Browser Version GPL Source Code.
|
||||
-->
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="pragma" content="no-cache" />
|
||||
<meta http-equiv="cache-control" content="max-age=0" />
|
||||
<meta http-equiv="cache-control" content="no-cache" />
|
||||
<meta http-equiv="cache-control" content="no-store" />
|
||||
<meta name="viewport" content="width=640, height=400, user-scalable=no">
|
||||
<link rel="shortcut icon" href="favicon.png" />
|
||||
<title>Wolfenstein 3D</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<script src="js/modernizr.custom.js"></script>
|
||||
<script src="js/jquery-1.7.1.min.js"></script>
|
||||
<script src="js/load.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
<div id="title-screen"></div>
|
||||
|
||||
<div id="menu">
|
||||
<div class="message confirm-newgame">
|
||||
<div class="box"></div>
|
||||
</div>
|
||||
|
||||
<div class="menu main">
|
||||
<ul class="selector">
|
||||
<li data-submenu="episodes" class="newgame"><div class="button"></div></li>
|
||||
<li data-submenu="sound" class="sound"><div class="button"></div></li>
|
||||
<li data-submenu="control" class="control"><div class="button"></div></li>
|
||||
<li class="readthis"><div class="button"></div></li>
|
||||
<li class="resumegame"><div class="button"></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu sound" data-backmenu="main">
|
||||
<ul class="selector">
|
||||
<li class="sfxon"><div class="button"><div class="light"></div></div></li>
|
||||
<li class="sfxoff"><div class="button"><div class="light"></div></div></li>
|
||||
<li class="musicon"><div class="button"><div class="light"></div></div></li>
|
||||
<li class="musicoff"><div class="button"><div class="light"></div></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu control" data-backmenu="main">
|
||||
<ul class="selector">
|
||||
<li class="mouseenabled"><div class="button"><div class="light"></div></div></li>
|
||||
<li data-submenu="customize" class="customize"><div class="button"></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu customize" data-backmenu="control">
|
||||
<ul class="selector">
|
||||
<li class="customizekeys line1"><div class="button">
|
||||
<span class="k1 run" data-action="run"></span>
|
||||
<span class="k2 use" data-action="use"></span>
|
||||
<span class="k3 attack" data-action="attack"></span>
|
||||
<span class="k4 strafe" data-action="strafe"></span>
|
||||
</div></li>
|
||||
<li class="customizekeys line1"><div class="button">
|
||||
<span class="k1 left" data-action="left"></span>
|
||||
<span class="k2 right" data-action="right"></span>
|
||||
<span class="k3 up" data-action="up"></span>
|
||||
<span class="k4 down" data-action="down"></span>
|
||||
</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu skill" data-backmenu="episodes">
|
||||
<div class="face"></div>
|
||||
<ul class="selector">
|
||||
<li data-submenu="levels" data-skill="gd_baby" class="baby"><div class="button"></div></li>
|
||||
<li data-submenu="levels" data-skill="gd_easy" class="easy"><div class="button"></div></li>
|
||||
<li data-submenu="levels" data-skill="gd_medium" class="medium"><div class="button"></div></li>
|
||||
<li data-submenu="levels" data-skill="gd_hard" class="hard"><div class="button"></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu episodes" data-backmenu="main">
|
||||
<ul>
|
||||
<li data-episode="0" class="episode-0"><div class="button"></div></li>
|
||||
<li data-episode="1" class="episode-1"><div class="button"></div></li>
|
||||
<li data-episode="2" class="episode-2"><div class="button"></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="menu levels" data-backmenu="skill">
|
||||
<ul class="two-column selector">
|
||||
<li data-level="0" class="level-0"><div class="button"></div></li>
|
||||
<li data-level="1" class="level-1"><div class="button"></div></li>
|
||||
<li data-level="2" class="level-2"><div class="button"></div></li>
|
||||
<li data-level="3" class="level-3"><div class="button"></div></li>
|
||||
<li data-level="4" class="level-4"><div class="button"></div></li>
|
||||
</ul>
|
||||
<ul class="two-column selector">
|
||||
<li data-level="5" class="level-5"><div class="button"></div></li>
|
||||
<li data-level="6" class="level-6"><div class="button"></div></li>
|
||||
<li data-level="7" class="level-7"><div class="button"></div></li>
|
||||
<li data-level="8" class="level-8"><div class="button"></div></li>
|
||||
<li data-level="9" class="level-9"><div class="button"></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="text-screen"></div>
|
||||
|
||||
|
||||
<div id="game">
|
||||
<div class="fps"></div>
|
||||
|
||||
<div class="renderer">
|
||||
<div class="ceiling"></div>
|
||||
<div class="floor"></div>
|
||||
<div class="player-weapon"></div>
|
||||
<div class="damage-flash overlay"></div>
|
||||
<div class="bonus-flash overlay"></div>
|
||||
<div class="death overlay"></div>
|
||||
<div class="pause overlay"><img alt="" src="art/paused.png"/></div>
|
||||
</div>
|
||||
|
||||
<div class="loading"><img alt="" src="art/getpsyched.png"/></div>
|
||||
|
||||
<div class="gameover"></div>
|
||||
|
||||
<div class="intermission">
|
||||
<div class="background"></div>
|
||||
<div class="background-secret"></div>
|
||||
<div class="background-victory"></div>
|
||||
|
||||
<div class="bj"></div>
|
||||
|
||||
<div class="floor stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
|
||||
<div class="bonus stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
|
||||
<div class="total-time-minutes victory-stat">
|
||||
<div class="digit"></div><div class="digit"></div>
|
||||
</div>
|
||||
<div class="total-time-seconds victory-stat">
|
||||
<div class="digit"></div><div class="digit"></div>
|
||||
</div>
|
||||
|
||||
<div class="time-minutes stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
<div class="time-seconds stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
<div class="par-minutes stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
<div class="par-seconds stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
|
||||
<div class="kill-ratio stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
<div class="secret-ratio stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
<div class="treasure-ratio stat">
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
<div class="digit"></div>
|
||||
</div>
|
||||
|
||||
<div class="avg-kill-ratio victory-stat">
|
||||
<div class="digit"></div><div class="digit"></div><div class="digit"></div>
|
||||
</div>
|
||||
<div class="avg-secret-ratio victory-stat">
|
||||
<div class="digit"></div><div class="digit"></div><div class="digit"></div>
|
||||
</div>
|
||||
<div class="avg-treasure-ratio victory-stat">
|
||||
<div class="digit"></div><div class="digit"></div><div class="digit"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hud">
|
||||
<div class="floor number-container">
|
||||
<div class="number"></div>
|
||||
</div>
|
||||
<div class="score number-container">
|
||||
<div class="number"></div><div class="number"></div><div class="number"></div><div class="number"></div><div class="number"></div><div class="number"></div>
|
||||
</div>
|
||||
<div class="lives number-container">
|
||||
<div class="number"></div>
|
||||
</div>
|
||||
<div class="health number-container">
|
||||
<div class="number"></div><div class="number"></div><div class="number"></div>
|
||||
</div>
|
||||
<div class="ammo number-container">
|
||||
<div class="number"></div><div class="number"></div>
|
||||
</div>
|
||||
<div class="key1"></div>
|
||||
<div class="key2"></div>
|
||||
<div class="bj"></div>
|
||||
<div class="weapon"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue