Squashed 'external/pure_doom/PureDOOM/' content from commit 5694fa4

git-subtree-dir: external/pure_doom/PureDOOM
git-subtree-split: 5694fa42089714cb3c9edc1c8e10e4e6b6e9adb9
This commit is contained in:
Green Sky 2024-03-08 21:33:52 +01:00
commit 0132cbcf33
139 changed files with 102888 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
build/
*.wad
.doomrc
references/
.DS_Store
.vscode
*.DLL

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "thirdparty/SDL"]
path = thirdparty/SDL
url = https://github.com/SDL-mirror/SDL.git
[submodule "thirdparty/SFML"]
path = thirdparty/SFML
url = https://github.com/SFML/SFML.git

5
CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.0)
project(PureDOOM)
add_subdirectory(examples/SDL)

339
LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General
Public License instead of this License.

48583
PureDOOM.h Normal file

File diff suppressed because it is too large Load Diff

266
README.md Normal file
View File

@ -0,0 +1,266 @@
![](images/PureDOOM.png)
# Pure DOOM
Header only, no dependencies DOOM source port. Designed to run on any devices.
Primarily of interest to people that want to "run DOOM on their microwave".
## LICENSE
See end of file for license information.
## Main Features:
- Single header
- Pure-C, No includes dependencies: no stdlib, stdio, etc.
- Supports 32 bits and 64 bits
## Other Features:
- Menu option to disable mouse move Forward/Backward
- Crosshair option
- Always-Run option
## TODOs
- Custom resolution
- Remove exit and have update return 0 on quit. Add doom_get_exit_code()
- Implement Sockets and Multiplayer
- Print message when discovered a secret
## Cool TODOs to have
- Rebindable keys
- Unlocked FPS
- Release mouse in menus and use it for clicking
- Wipe screen freezes menu
- Use floats instead of fixed_t
- French and german
- Full color mode (Don't use COLORMAPS, use full 24 bits RGB)
## Usage
Call `doom_init()`, then call `doom_update()` every frame, or as often as you can. This will run DOOM, without any video, inputs, sounds or music.
```c
#define DOOM_IMPLEMENTATION
#include "PureDOOM.h"
int main(int argc, char** argv)
{
doom_init(argc, argv, 0);
while (true)
{
doom_update();
}
}
```
## Enable features
Most standard headers are available on most platforms. Define these preprocessors to toggle these features.
- `DOOM_IMPLEMENT_PRINT`. Allows printf, requires `<stdio.h>`
- `DOOM_IMPLEMENT_MALLOC`. Allows malloc/free, requires `<stdlib.h>`
- `DOOM_IMPLEMENT_FILE_IO`. Allows FILE, requires `<stdio.h>`
- `DOOM_IMPLEMENT_GETTIME`. Requires `<sys/time.h>` or `<winsock.h>`
- `DOOM_IMPLEMENT_EXIT`. Allows exit(), requires `<stdlib.h>`
- `DOOM_IMPLEMENT_GETENV`. Requires `<stdlib.h>`
If your microwave doesn't have these headers, you can override their default implementations:
```c
void doom_set_print(doom_print_fn print_fn);
void doom_set_malloc(doom_malloc_fn malloc_fn, doom_free_fn free_fn);
void doom_set_file_io(doom_open_fn open_fn,
doom_close_fn close_fn,
doom_read_fn read_fn,
doom_write_fn write_fn,
doom_seek_fn seek_fn,
doom_tell_fn tell_fn,
doom_eof_fn eof_fn);
void doom_set_gettime(doom_gettime_fn gettime_fn);
void doom_set_exit(doom_exit_fn exit_fn);
void doom_set_getenv(doom_getenv_fn getenv_fn);
```
## Video
Every frame, after having called `doom_update()`, you can get the screen pixels with `doom_get_framebuffer` and display it as you please.
```c
while (true)
{
doom_update();
uint8_t* framebuffer = doom_get_framebuffer(4 /* RGBA */);
// ... Display framebuffer
}
```
## Inputs
When you receive input events from your microwave touch pad, simply call one of the DOOM input events:
```c
void doom_key_down(doom_key_t key);
void doom_key_up(doom_key_t key);
void doom_button_down(doom_button_t button);
void doom_button_up(doom_button_t button);
void doom_mouse_move(int delta_x, int delta_y);
```
## Sounds
Create a sound thread that outputs at 11025hz (`DOOM_SAMPLERATE`), 512 samples, 16 bits, stereo. Then in your sound callback, call `doom_get_sound_buffer` to update and get the current DOOM's sound output. Make sure to add synchronization primitives around this and `doom_update` if your sound loop is in a thread.
Here is a quick example using SDL audio callback:
```c
void sdl_audio_callback(void* userdata, Uint8* stream, int len)
{
SDL_LockAudio();
int16_t* buffer = doom_get_sound_buffer(len);
SDL_UnlockAudio();
memcpy(stream, buffer, len);
}
```
You can use different bitrate, but make sure to resample because DOOM will always be 11025hz, 512 samples, 16 bits, 2 channels. For a total for 2048 bytes per buffer.
## Music
Set a timer in your application that runs at 140hz. In the timer's callback, tick DOOM's music as long as there are MIDI messages to send.
Here is an example using Window's MultiMedia to play MIDI events, using an SDL timer.
```c
Uint32 tick_music(Uint32 interval, void *param)
{
uint32_t midi_msg;
SDL_LockAudio();
while (midi_msg = doom_tick_midi())
midiOutShortMsg(midi_out_handle, midi_msg);
SDL_UnlockAudio();
return 1000 / DOOM_MIDI_RATE /* 140 */;
}
```
## Change default settings
Default input setup in DOOM's source is not modern. It uses Arrows to move and `','` / `'.'` to strafe. You can call `doom_set_default_int` and `doom_set_default_str` to change them:
```c
// Change default bindings to modern mapping
doom_set_default_int("key_up", DOOM_KEY_W);
doom_set_default_int("key_down", DOOM_KEY_S);
doom_set_default_int("key_strafeleft", DOOM_KEY_A);
doom_set_default_int("key_straferight", DOOM_KEY_D);
doom_set_default_int("key_use", DOOM_KEY_E);
doom_set_default_int("mouse_move", 0); // Mouse will not move forward
```
Refer to the defaults in `m_misc.cpp` for the complete list.
## Working SDL Example
See the file `src/sdl_example.c` for a complete SDL example.
# DOOM LICENSE
```
LIMITED USE SOFTWARE LICENSE AGREEMENT
This Limited Use Software License Agreement (the "Agreement")
is a legal agreement between you, the end-user, and Id Software, Inc.
("ID"). By downloading or purchasing the software material, which
includes source code (the "Source Code"), artwork data, music and
software tools (collectively, the "Software"), you are agreeing to
be bound by the terms of this Agreement. If you do not agree to the
terms of this Agreement, promptly destroy the Software you may have
downloaded or copied.
ID SOFTWARE LICENSE
1. Grant of License. ID grants to you the right to use the
Software. You have no ownership or proprietary rights in or to the
Software, or the Trademark. For purposes of this section, "use" means
loading the Software into RAM, as well as installation on a hard disk
or other storage device. The Software, together with any archive copy
thereof, shall be destroyed when no longer used in accordance with
this Agreement, or when the right to use the Software is terminated.
You agree that the Software will not be shipped, transferred or
exported into any country in violation of the U.S. Export
Administration Act (or any other law governing such matters) and that
you will not utilize, in any other manner, the Software in violation
of any applicable law.
2. Permitted Uses. For educational purposes only, you, the
end-user, may use portions of the Source Code, such as particular
routines, to develop your own software, but may not duplicate the
Source Code, except as noted in paragraph 4. The limited right
referenced in the preceding sentence is hereinafter referred to as
"Educational Use." By so exercising the Educational Use right you
shall not obtain any ownership, copyright, proprietary or other
interest in or to the Source Code, or any portion of the Source
Code. You may dispose of your own software in your sole discretion.
With the exception of the Educational Use right, you may not
otherwise use the Software, or an portion of the Software, which
includes the Source Code, for commercial gain.
3. Prohibited Uses: Under no circumstances shall you, the
end-user, be permitted, allowed or authorized to commercially exploit
the Software. Neither you nor anyone at your direction shall do any
of the following acts with regard to the Software, or any portion
thereof:
Rent;
Sell;
Lease;
Offer on a pay-per-play basis;
Distribute for money or any other consideration; or
In any other manner and through any medium whatsoever
commercially exploit or use for any commercial purpose.
Notwithstanding the foregoing prohibitions, you may commercially
exploit the software you develop by exercising the Educational Use
right, referenced in paragraph 2. hereinabove.
4. Copyright. The Software and all copyrights related thereto
(including all characters and other images generated by the Software
or depicted in the Software) are owned by ID and is protected by
United States copyright laws and international treaty provisions.
Id shall retain exclusive ownership and copyright in and to the
Software and all portions of the Software and you shall have no
ownership or other proprietary interest in such materials. You must
treat the Software like any other copyrighted material. You may not
otherwise reproduce, copy or disclose to others, in whole or in any
part, the Software. You may not copy the written materials
accompanying the Software. You agree to use your best efforts to
see that any user of the Software licensed hereunder complies with
this Agreement.
5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS
IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT
TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO
JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE
WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS.
THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS
WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES,
DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE
MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF
OF ID.
Exclusive Remedies. The Software is being offered to you
free of any charge. You agree that you have no remedy against ID, its
affiliates, contractors, suppliers, and agents for loss or damage
caused by any defect or failure in the Software regardless of the form
of action, whether in contract, tort, includinegligence, strict
liability or otherwise, with regard to the Software. This Agreement
shall be construed in accordance with and governed by the laws of the
State of Texas. Copyright and other proprietary matters will be
governed by United States laws and international treaties. IN ANY
CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST
SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER
SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT,
NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
OTHER PARTY. Some jurisdictions do not allow the exclusion or
limitation of incidental or consequential damages, so the above
limitation or exclusion may not apply to you.
```

View File

@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.0)
# Project
project(pd_sdl_example)
# add_definitions(-DDOOM_FAST_TICK)
add_definitions(
-DDOOM_IMPLEMENT_PRINT
-DDOOM_IMPLEMENT_MALLOC
-DDOOM_IMPLEMENT_FILE_IO
-DDOOM_IMPLEMENT_SOCKETS
-DDOOM_IMPLEMENT_GETTIME
-DDOOM_IMPLEMENT_EXIT
-DDOOM_IMPLEMENT_GETENV
)
# Sources
file(GLOB dpsdl_src_files sdl_example.c)
file(GLOB dpsdl_doom_src_files ../../src/DOOM/*.*)
list(APPEND dpsdl_includes PUBLIC ../../src/)
# SDL
add_definitions(-DSDL_MAIN_HANDLED)
set(HAVE_LIBC ON)
add_subdirectory(../../thirdparty/SDL/ ./thirdparty/SDL/)
list(APPEND dpsdl_libs SDL2-static)
list(APPEND dpsdl_includes PUBLIC ../../thirdparty/SDL/include/)
# Source groups
source_group("Example" FILES ${dpsdl_src_files})
source_group("DOOM" FILES ${dpsdl_doom_src_files})
# Executable
add_executable(${PROJECT_NAME} ${dpsdl_src_files})
# Work dir
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../")
# For midi output on mac
if (APPLE)
list(APPEND dpsdl_libs "-framework CoreFoundation")
list(APPEND dpsdl_libs "-framework AudioToolbox")
list(APPEND dpsdl_libs "-framework CoreMIDI")
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-F/Library/Frameworks")
endif()
# Lib/Headers
target_include_directories(${PROJECT_NAME} PUBLIC ${dpsdl_includes})
target_link_libraries(${PROJECT_NAME} PUBLIC ${dpsdl_libs})

514
examples/SDL/sdl_example.c Normal file
View File

@ -0,0 +1,514 @@
#if defined(WIN32)
#pragma comment(lib, "winmm.lib")
#include <Windows.h>
#include <mmeapi.h>
#elif defined(__APPLE__)
#include <AudioToolbox/AudioToolbox.h>
#include <CoreFoundation/CoreFoundation.h>
#endif
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#if 1 // Use the PureDOOM.h single header
#define DOOM_IMPLEMENTATION
#include "../../PureDOOM.h"
#else
#include "DOOM/DOOM.h"
#endif
// Palette experiments
//#define PICO8 1
//#define CGA 1
//#define GAME_BOY 1
// Resolution DOOM renders at
#define WIDTH 320
#define HEIGHT 200
#define SCALE 4
// Resolution of the SDL window
#define FULL_WIDTH (WIDTH * SCALE)
#define FULL_HEIGHT (int)(HEIGHT * 1.2 * SCALE) // 1.2x higher than DOOM's height. Original game was designed stretched
doom_key_t sdl_scancode_to_doom_key(SDL_Scancode scancode)
{
switch (scancode)
{
case SDL_SCANCODE_TAB: return DOOM_KEY_TAB;
case SDL_SCANCODE_RETURN: return DOOM_KEY_ENTER;
case SDL_SCANCODE_ESCAPE: return DOOM_KEY_ESCAPE;
case SDL_SCANCODE_SPACE: return DOOM_KEY_SPACE;
case SDL_SCANCODE_APOSTROPHE: return DOOM_KEY_APOSTROPHE;
case SDL_SCANCODE_KP_MULTIPLY: return DOOM_KEY_MULTIPLY;
case SDL_SCANCODE_COMMA: return DOOM_KEY_COMMA;
case SDL_SCANCODE_MINUS: return DOOM_KEY_MINUS;
case SDL_SCANCODE_PERIOD: return DOOM_KEY_PERIOD;
case SDL_SCANCODE_SLASH: return DOOM_KEY_SLASH;
case SDL_SCANCODE_0: return DOOM_KEY_0;
case SDL_SCANCODE_1: return DOOM_KEY_1;
case SDL_SCANCODE_2: return DOOM_KEY_2;
case SDL_SCANCODE_3: return DOOM_KEY_3;
case SDL_SCANCODE_4: return DOOM_KEY_4;
case SDL_SCANCODE_5: return DOOM_KEY_5;
case SDL_SCANCODE_6: return DOOM_KEY_6;
case SDL_SCANCODE_7: return DOOM_KEY_7;
case SDL_SCANCODE_8: return DOOM_KEY_8;
case SDL_SCANCODE_9: return DOOM_KEY_9;
case SDL_SCANCODE_SEMICOLON: return DOOM_KEY_SEMICOLON;
case SDL_SCANCODE_EQUALS: return DOOM_KEY_EQUALS;
case SDL_SCANCODE_LEFTBRACKET: return DOOM_KEY_LEFT_BRACKET;
case SDL_SCANCODE_RIGHTBRACKET: return DOOM_KEY_RIGHT_BRACKET;
case SDL_SCANCODE_A: return DOOM_KEY_A;
case SDL_SCANCODE_B: return DOOM_KEY_B;
case SDL_SCANCODE_C: return DOOM_KEY_C;
case SDL_SCANCODE_D: return DOOM_KEY_D;
case SDL_SCANCODE_E: return DOOM_KEY_E;
case SDL_SCANCODE_F: return DOOM_KEY_F;
case SDL_SCANCODE_G: return DOOM_KEY_G;
case SDL_SCANCODE_H: return DOOM_KEY_H;
case SDL_SCANCODE_I: return DOOM_KEY_I;
case SDL_SCANCODE_J: return DOOM_KEY_J;
case SDL_SCANCODE_K: return DOOM_KEY_K;
case SDL_SCANCODE_L: return DOOM_KEY_L;
case SDL_SCANCODE_M: return DOOM_KEY_M;
case SDL_SCANCODE_N: return DOOM_KEY_N;
case SDL_SCANCODE_O: return DOOM_KEY_O;
case SDL_SCANCODE_P: return DOOM_KEY_P;
case SDL_SCANCODE_Q: return DOOM_KEY_Q;
case SDL_SCANCODE_R: return DOOM_KEY_R;
case SDL_SCANCODE_S: return DOOM_KEY_S;
case SDL_SCANCODE_T: return DOOM_KEY_T;
case SDL_SCANCODE_U: return DOOM_KEY_U;
case SDL_SCANCODE_V: return DOOM_KEY_V;
case SDL_SCANCODE_W: return DOOM_KEY_W;
case SDL_SCANCODE_X: return DOOM_KEY_X;
case SDL_SCANCODE_Y: return DOOM_KEY_Y;
case SDL_SCANCODE_Z: return DOOM_KEY_Z;
case SDL_SCANCODE_BACKSPACE: return DOOM_KEY_BACKSPACE;
case SDL_SCANCODE_LCTRL:
case SDL_SCANCODE_RCTRL: return DOOM_KEY_CTRL;
case SDL_SCANCODE_LEFT: return DOOM_KEY_LEFT_ARROW;
case SDL_SCANCODE_UP: return DOOM_KEY_UP_ARROW;
case SDL_SCANCODE_RIGHT: return DOOM_KEY_RIGHT_ARROW;
case SDL_SCANCODE_DOWN: return DOOM_KEY_DOWN_ARROW;
case SDL_SCANCODE_LSHIFT:
case SDL_SCANCODE_RSHIFT: return DOOM_KEY_SHIFT;
case SDL_SCANCODE_LALT:
case SDL_SCANCODE_RALT: return DOOM_KEY_ALT;
case SDL_SCANCODE_F1: return DOOM_KEY_F1;
case SDL_SCANCODE_F2: return DOOM_KEY_F2;
case SDL_SCANCODE_F3: return DOOM_KEY_F3;
case SDL_SCANCODE_F4: return DOOM_KEY_F4;
case SDL_SCANCODE_F5: return DOOM_KEY_F5;
case SDL_SCANCODE_F6: return DOOM_KEY_F6;
case SDL_SCANCODE_F7: return DOOM_KEY_F7;
case SDL_SCANCODE_F8: return DOOM_KEY_F8;
case SDL_SCANCODE_F9: return DOOM_KEY_F9;
case SDL_SCANCODE_F10: return DOOM_KEY_F10;
case SDL_SCANCODE_F11: return DOOM_KEY_F11;
case SDL_SCANCODE_F12: return DOOM_KEY_F12;
case SDL_SCANCODE_PAUSE: return DOOM_KEY_PAUSE;
default: return DOOM_KEY_UNKNOWN;
}
return DOOM_KEY_UNKNOWN;
}
doom_button_t sdl_button_to_doom_button(Uint8 sdl_button)
{
switch (sdl_button)
{
case SDL_BUTTON_LEFT: return DOOM_LEFT_BUTTON;
case SDL_BUTTON_RIGHT: return DOOM_RIGHT_BUTTON;
case SDL_BUTTON_MIDDLE: return DOOM_MIDDLE_BUTTON;
}
return (doom_button_t)0;
}
void audio_callback(void* userdata, Uint8* stream, int len)
{
SDL_LockAudio();
int16_t* buffer = doom_get_sound_buffer();
SDL_UnlockAudio();
memcpy(stream, buffer, len);
}
#if defined(WIN32)
static HMIDIOUT midi_out_handle = 0;
void send_midi_msg(uint32_t midi_msg)
{
if (midi_out_handle)
{
midiOutShortMsg(midi_out_handle, midi_msg);
}
}
#elif defined(__APPLE__)
AudioUnit audio_unit = 0;
void send_midi_msg(uint32_t midi_msg)
{
if (audio_unit)
{
MusicDeviceMIDIEvent(audio_unit,
(midi_msg) & 0xFF,
(midi_msg >> 8) & 0xFF,
(midi_msg >> 16) & 0xFF,
0);
}
}
#else
void send_midi_msg(uint32_t midi_msg) {}
#endif
SDL_TimerID midi_timer = 0;
Uint32 tick_midi(Uint32 interval, void *param)
{
uint32_t midi_msg;
SDL_LockAudio();
while ((midi_msg = doom_tick_midi()) != 0) send_midi_msg(midi_msg);
SDL_UnlockAudio();
#if defined(__APPLE__)
return 1000 / DOOM_MIDI_RATE - 1; // Weirdly, on Apple music is too slow
#else
return 1000 / DOOM_MIDI_RATE;
#endif
}
int main(int argc, char** argv)
{
// Init SDL
SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER);
SDL_Window* window = SDL_CreateWindow("Pure DOOM - SDL Example",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
FULL_WIDTH, FULL_HEIGHT,
SDL_WINDOW_RESIZABLE);
// SDL Renderer
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
SDL_Texture* render_target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT);
// SDL Audio thread
SDL_AudioSpec audio_spec;
memset(&audio_spec, 0, sizeof(audio_spec));
audio_spec.freq = DOOM_SAMPLERATE;
audio_spec.format = AUDIO_S16;
audio_spec.channels = 2;
audio_spec.samples = 512;
audio_spec.callback = audio_callback;
if (SDL_OpenAudio(&audio_spec, NULL) < 0)
{
printf("Failed to SDL_OpenAudio\n");
return 1;
}
// Capture mouse
SDL_SetRelativeMouseMode(SDL_TRUE);
//-----------------------------------------------------------------------
// Setup DOOM
//-----------------------------------------------------------------------
// Change default bindings to modern
doom_set_default_int("key_up", DOOM_KEY_W);
doom_set_default_int("key_down", DOOM_KEY_S);
doom_set_default_int("key_strafeleft", DOOM_KEY_A);
doom_set_default_int("key_straferight", DOOM_KEY_D);
doom_set_default_int("key_use", DOOM_KEY_E);
doom_set_default_int("mouse_move", 0); // Mouse will not move forward
// Setup resolution
doom_set_resolution(WIDTH, HEIGHT);
// Setup MIDI for songs
#if defined(WIN32)
if (midiOutGetNumDevs() != 0)
midiOutOpen(&midi_out_handle, 0, 0, 0, 0);
#elif defined(__APPLE__)
// I don't really understand this part, but it works.
AUGraph graph;
AUNode outputNode, mixerNode, dlsNode;
NewAUGraph(&graph);
AudioComponentDescription output = {'auou','ahal','appl',0,0};
AUGraphAddNode(graph, &output, &outputNode);
AUGraphOpen(graph);
AUGraphInitialize(graph);
AUGraphStart(graph);
AudioComponentDescription dls = {'aumu','dls ','appl',0,0};
AUGraphAddNode(graph, &dls, &dlsNode);
AUGraphNodeInfo(graph, dlsNode, NULL, &audio_unit);
AudioComponentDescription mixer = {'aumx','smxr','appl',0,0};
AUGraphAddNode(graph, &mixer, &mixerNode);
AUGraphConnectNodeInput(graph,mixerNode,0,outputNode,0);
AUGraphConnectNodeInput(graph,dlsNode,0,mixerNode,0);
AUGraphUpdate(graph,NULL);
#endif
midi_timer = SDL_AddTimer(0, tick_midi, 0);
// Initialize doom
doom_init(argc, argv, DOOM_FLAG_MENU_DARKEN_BG);
//-----------------------------------------------------------------------
// Main loop
SDL_PauseAudio(0);
int done = 0;
int active_mouse = 1; // Dev allow us to take mouse out of window
while (!done)
{
SDL_Event e;
Sint32 mouse_motion_x = 0;
Sint32 mouse_motion_y = 0;
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_QUIT:
done = 1;
break;
case SDL_KEYDOWN:
if (e.key.keysym.scancode == SDL_SCANCODE_END)
{
active_mouse = !active_mouse;
SDL_SetRelativeMouseMode(active_mouse ? SDL_TRUE : SDL_FALSE);
}
if (!e.key.repeat)
doom_key_down(sdl_scancode_to_doom_key(e.key.keysym.scancode));
break;
case SDL_KEYUP:
if (!e.key.repeat)
doom_key_up(sdl_scancode_to_doom_key(e.key.keysym.scancode));
break;
case SDL_MOUSEBUTTONDOWN:
if (active_mouse) doom_button_down(sdl_button_to_doom_button(e.button.button));
break;
case SDL_MOUSEBUTTONUP:
if (active_mouse) doom_button_up(sdl_button_to_doom_button(e.button.button));
break;
case SDL_MOUSEMOTION:
if (active_mouse)
{
mouse_motion_x += e.motion.xrel;
mouse_motion_y += e.motion.yrel;
}
break;
}
if (done) break;
}
if (done) break;
if (mouse_motion_x || mouse_motion_y)
doom_mouse_move(mouse_motion_x * 4, mouse_motion_y * 4);
SDL_LockAudio();
doom_update();
SDL_UnlockAudio();
// Blit DOOM's framebuffer onto our SDL texture
#if GAME_BOY
void* dst;
const unsigned char* src = doom_get_framebuffer(3);
int src_pitch = WIDTH * 3;
int dst_pitch;
const int palette_size = 4;
const int pico8_palette[4 * 3] = {
0x0f, 0x3, 0x80f,
0x30, 0x62, 0x30,
0x8b, 0xac, 0x0f,
0x9b, 0xbc, 0x0f
};
if (!SDL_LockTexture(render_target, NULL, &dst, &dst_pitch))
{
unsigned char* dst8 = (unsigned char*)dst;
for (int y = 0; y < HEIGHT; ++y)
{
for (int x = 0; x < WIDTH; ++x)
{
int dstk = y * dst_pitch + x * 4;
int srck = y * src_pitch + x * 3;
int r = src[srck + 0];
int g = src[srck + 1];
int b = src[srck + 2];
int best = 0;
int best_score = (r * r + g * g + b * b) * 2;
for (int p = 0; p < palette_size * 3; p += 3)
{
const int* pico8_color = pico8_palette + p;
if (pico8_color[0] == r &&
pico8_color[1] == g &&
pico8_color[2] == b)
{
// Perfect match
best = p;
break;
}
int ri = pico8_color[0] - r;
int gi = pico8_color[1] - g;
int bi = pico8_color[2] - b;
int score = ri * ri + gi * gi + bi * bi;
if (score < best_score)
{
best_score = score;
best = p;
}
}
dst8[dstk + 0] = pico8_palette[best + 0];
dst8[dstk + 1] = pico8_palette[best + 1];
dst8[dstk + 2] = pico8_palette[best + 2];
dst8[dstk + 3] = 255;
}
}
SDL_UnlockTexture(render_target);
}
#elif PICO8 || CGA
void* dst;
const unsigned char* src = doom_get_framebuffer(3);
int src_pitch = WIDTH * 3;
int dst_pitch;
#if CGA
const int palette_size = 16;
const int pico8_palette[16 * 3] = {
0, 0, 0,
0, 0, 0xAA,
0, 0xAA, 0,
0, 0xAA, 0xAA,
0xAA, 0, 0,
0xAA, 0, 0xAA,
0xAA, 0x55, 0,
0xAA, 0xAA, 0xAA,
0x55, 0x55, 0x55,
0x55, 0x55, 0xFF,
0x55, 0xFF, 0x55,
0x55, 0xFF, 0xFF,
0xFF, 0x55, 0x55,
0xFF, 0x55, 0xFF,
0xFF, 0xFF, 0x55,
0xFF, 0xFF, 0xFF
};
#elif PICO8
const int palette_size = 16;
const int pico8_palette[16 * 3] = {
0, 0, 0,
29, 43, 83,
126, 37, 83,
0, 135, 81,
171, 82, 54,
95, 87, 79,
194, 195, 199,
255, 241, 232,
255, 0, 77,
255, 163, 0,
255, 236, 39,
0, 228, 54,
41, 173, 255,
131, 118, 156,
255, 119, 168,
255, 204, 170
};
#endif
if (!SDL_LockTexture(render_target, NULL, &dst, &dst_pitch))
{
unsigned char* dst8 = (unsigned char*)dst;
for (int y = 0; y < HEIGHT; ++y)
{
for (int x = 0; x < WIDTH; ++x)
{
int dstk = y * dst_pitch + x * 4;
int srck = y * src_pitch + x * 3;
int r = src[srck + 0];
int g = src[srck + 1];
int b = src[srck + 2];
int best = 0;
int best_score = (r * r + g * g + b * b) * 2;
for (int p = 0; p < palette_size * 3; p += 3)
{
const int* pico8_color = pico8_palette + p;
if (pico8_color[0] == r &&
pico8_color[1] == g &&
pico8_color[2] == b)
{
// Perfect match
best = p;
break;
}
int ri = pico8_color[0] - r;
int gi = pico8_color[1] - g;
int bi = pico8_color[2] - b;
int score = ri * ri + gi * gi + bi * bi;
if (score < best_score)
{
best_score = score;
best = p;
}
}
dst8[dstk + 0] = pico8_palette[best + 0];
dst8[dstk + 1] = pico8_palette[best + 1];
dst8[dstk + 2] = pico8_palette[best + 2];
dst8[dstk + 3] = 255;
}
}
SDL_UnlockTexture(render_target);
}
#else
void* dst;
const unsigned char* src = doom_get_framebuffer(4);
int src_pitch = WIDTH * 4;
int dst_pitch;
if (!SDL_LockTexture(render_target, NULL, &dst, &dst_pitch))
{
for (int y = 0; y < HEIGHT; ++y)
{
memcpy(dst, src, src_pitch);
dst = (unsigned char*)dst + dst_pitch;
src += src_pitch;
}
SDL_UnlockTexture(render_target);
}
#endif
// Stretch our texture on the screen
SDL_Rect src_rect = {0, 0, WIDTH, HEIGHT };
SDL_Rect dst_rect = {0, 0, FULL_WIDTH, FULL_HEIGHT};
SDL_RenderCopy(renderer, render_target, &src_rect, &dst_rect);
// Swap
SDL_RenderPresent(renderer);
}
// Shutdown
if (midi_timer) SDL_RemoveTimer(midi_timer);
#if defined(WIN32)
if (midi_out_handle) midiOutClose(midi_out_handle);
#endif
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_CloseAudio();
SDL_DestroyTexture(render_target);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

BIN
images/PureDOOM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

739
src/DOOM/DOOM.c Normal file
View File

@ -0,0 +1,739 @@
#if defined(WIN32)
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#include "DOOM.h"
#include "d_main.h"
#include "doomdef.h"
#include "doomtype.h"
#include "i_system.h"
#include "m_argv.h"
#include "m_misc.h"
extern byte* screens[5];
extern unsigned char screen_palette[256 * 3];
extern doom_boolean is_wiping_screen;
extern default_t defaults[];
extern int numdefaults;
extern signed short mixbuffer[2048];
static unsigned char* screen_buffer = 0;
static unsigned char* final_screen_buffer = 0;
static int last_update_time = 0;
static int button_states[3] = { 0 };
static char itoa_buf[20];
char error_buf[260];
int doom_flags = 0;
doom_print_fn doom_print = 0;
doom_malloc_fn doom_malloc = 0;
doom_free_fn doom_free = 0;
doom_open_fn doom_open = 0;
doom_close_fn doom_close = 0;
doom_read_fn doom_read = 0;
doom_write_fn doom_write = 0;
doom_seek_fn doom_seek = 0;
doom_tell_fn doom_tell = 0;
doom_eof_fn doom_eof = 0;
doom_gettime_fn doom_gettime = 0;
doom_exit_fn doom_exit = 0;
doom_getenv_fn doom_getenv = 0;
void D_DoomLoop(void);
void D_UpdateWipe(void);
void I_UpdateSound();
unsigned long I_TickSong();
#if defined(DOOM_IMPLEMENT_PRINT)
#include <stdio.h>
static void doom_print_impl(const char* str)
{
printf("%s", str);
}
#else
static void doom_print_impl(const char* str) {}
#endif
#if defined(DOOM_IMPLEMENT_MALLOC)
#include <stdlib.h>
static void* doom_malloc_impl(int size)
{
return malloc((size_t)size);
}
static void doom_free_impl(void* ptr)
{
free(ptr);
}
#else
static void* doom_malloc_impl(int size) { return 0; }
static void doom_free_impl(void* ptr) {}
#endif
#if defined(DOOM_IMPLEMENT_FILE_IO)
#include <stdio.h>
void* doom_open_impl(const char* filename, const char* mode)
{
return fopen(filename, mode);
}
void doom_close_impl(void* handle)
{
fclose(handle);
}
int doom_read_impl(void* handle, void *buf, int count)
{
return (int)fread(buf, 1, count, handle);
}
int doom_write_impl(void* handle, const void *buf, int count)
{
return (int)fwrite(buf, 1, count, handle);
}
int doom_seek_impl(void* handle, int offset, doom_seek_t origin)
{
return fseek(handle, offset, origin);
}
int doom_tell_impl(void* handle)
{
return (int)ftell(handle);
}
int doom_eof_impl(void* handle)
{
return feof(handle);
}
#else
void* doom_open_impl(const char* filename, const char* mode)
{
return 0;
}
void doom_close_impl(void* handle) {}
int doom_read_impl(void* handle, void *buf, int count)
{
return -1;
}
int doom_write_impl(void* handle, const void *buf, int count)
{
return -1;
}
int doom_seek_impl(void* handle, int offset, doom_seek_t origin)
{
return -1;
}
int doom_tell_impl(void* handle)
{
return -1;
}
int doom_eof_impl(void* handle)
{
return 1;
}
#endif
#if defined(DOOM_IMPLEMENT_GETTIME)
#if defined(WIN32)
#include <winsock.h>
#else
#include <sys/time.h>
#endif
void doom_gettime_impl(int* sec, int* usec)
{
#if defined(WIN32)
static const unsigned long long EPOCH = ((unsigned long long)116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
unsigned long long time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((unsigned long long)file_time.dwLowDateTime);
time += ((unsigned long long)file_time.dwHighDateTime) << 32;
*sec = (int)((time - EPOCH) / 10000000L);
*usec = (int)(system_time.wMilliseconds * 1000);
#else
struct timeval tp;
struct timezone tzp;
gettimeofday(&tp, &tzp);
*sec = tp.tv_sec;
*usec = tp.tv_usec;
#endif
}
#else
void doom_gettime_impl(int* sec, int* usec)
{
*sec = 0;
*usec = 0;
}
#endif
#if defined(DOOM_IMPLEMENT_EXIT)
#include <stdlib.h>
void doom_exit_impl(int code)
{
exit(code);
}
#else
void doom_exit_impl(int code) {}
#endif
#if defined(DOOM_IMPLEMENT_GETENV)
#include <stdlib.h>
char* doom_getenv_impl(const char* var)
{
return getenv(var);
}
#else
char* doom_getenv_impl(const char* var) { return 0; }
#endif
void doom_memset(void* ptr, int value, int num)
{
unsigned char* p = ptr;
for (int i = 0; i < num; ++i, ++p)
{
*p = (unsigned char)value;
}
}
void* doom_memcpy(void* destination, const void* source, int num)
{
unsigned char* dst = destination;
const unsigned char* src = source;
for (int i = 0; i < num; ++i, ++dst, ++src)
{
*dst = *src;
}
return destination;
}
int doom_strlen(const char* str)
{
int len = 0;
while (*str++) ++len;
return len;
}
char* doom_concat(char* dst, const char* src)
{
char* ret = dst;
dst += doom_strlen(dst);
while (*src) *dst++ = *src++;
*dst = *src; // \0
return ret;
}
char* doom_strcpy(char* dst, const char* src)
{
char* ret = dst;
while (*src) *dst++ = *src++;
*dst = *src; // \0
return ret;
}
char* doom_strncpy(char* dst, const char* src, int num)
{
int i = 0;
for (; i < num; ++i)
{
if (!src[i]) break;
dst[i] = src[i];
}
while (i < num) dst[i++] = '\0';
return dst;
}
int doom_strcmp(const char* str1, const char* str2)
{
int ret = 0;
while (!(ret = *(unsigned char*)str1 - *(unsigned char*) str2) && *str1)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_strncmp(const char* str1, const char* str2, int n)
{
int ret = 0;
int count = 1;
while (!(ret = *(unsigned char*)str1 - *(unsigned char*) str2) && *str1 && count++ < n)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_toupper(int c)
{
if (c >= 'a' && c <= 'z') return c - 'a' + 'A';
return c;
}
int doom_strcasecmp(const char* str1, const char* str2)
{
int ret = 0;
while (!(ret = doom_toupper(*(unsigned char*)str1) - doom_toupper(*(unsigned char*)str2)) && *str1)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_strncasecmp(const char* str1, const char* str2, int n)
{
int ret = 0;
int count = 1;
while (!(ret = doom_toupper(*(unsigned char*)str1) - doom_toupper(*(unsigned char*)str2)) && *str1 && count++ < n)
++str1, ++str2;
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1;
return (ret);
}
int doom_atoi(const char* str)
{
int i = 0;
int c;
while ((c = *str++) != 0)
{
i *= 10;
i += c - '0';
}
return i;
}
int doom_atox(const char* str)
{
int i = 0;
int c;
while ((c = *str++) != 0)
{
i *= 16;
if (c >= '0' && c <= '9')
i += c - '0';
else
i += c - 'A' + 10;
}
return i;
}
const char* doom_itoa(int k, int radix)
{
int i = k < 0 ? -k : k;
if (i == 0)
{
itoa_buf[0] = '0';
itoa_buf[1] = '\0';
return itoa_buf;
}
int idx = k < 0 ? 1 : 0;
int j = i;
while (j)
{
j /= radix;
idx++;
}
itoa_buf[idx] = '\0';
if (radix == 10)
{
while (i)
{
itoa_buf[--idx] = '0' + (i % 10);
i /= 10;
}
}
else
{
while (i)
{
int k = (i & 0xF);
if (k >= 10)
itoa_buf[--idx] = 'A' + ((i & 0xF) - 10);
else
itoa_buf[--idx] = '0' + (i & 0xF);
i >>= 4;
}
}
if (k < 0) itoa_buf[0] = '-';
return itoa_buf;
}
const char* doom_ctoa(char c)
{
itoa_buf[0] = c;
itoa_buf[1] = '\0';
return itoa_buf;
}
const char* doom_ptoa(void* p)
{
int idx = 0;
unsigned long long i = (unsigned long long)p;
itoa_buf[idx++] = '0';
itoa_buf[idx++] = 'x';
while (i)
{
int k = (i & 0xF);
if (k >= 10)
itoa_buf[idx++] = 'A' + ((i & 0xF) - 10);
else
itoa_buf[idx++] = '0' + (i & 0xF);
i >>= 4;
}
itoa_buf[idx] = '\0';
return itoa_buf;
}
int doom_fprint(void* handle, const char* str)
{
return doom_write(handle, str, doom_strlen(str));
}
static default_t* get_default(const char* name)
{
for (int i = 0; i < numdefaults; ++i)
{
if (doom_strcmp(defaults[i].name, name) == 0) return &defaults[i];
}
return 0;
}
void doom_set_resolution(int width, int height)
{
if (width <= 0 || height <= 0) return;
// SCREENWIDTH = width;
// SCREENHEIGHT = height;
}
void doom_set_default_int(const char* name, int value)
{
default_t* def = get_default(name);
if (!def) return;
def->defaultvalue = value;
}
void doom_set_default_string(const char* name, const char* value)
{
default_t* def = get_default(name);
if (!def) return;
def->default_text_value = (char*)value;
}
void doom_set_print(doom_print_fn print_fn)
{
doom_print = print_fn;
}
void doom_set_malloc(doom_malloc_fn malloc_fn, doom_free_fn free_fn)
{
doom_malloc = malloc_fn;
doom_free = free_fn;
}
void doom_set_file_io(doom_open_fn open_fn,
doom_close_fn close_fn,
doom_read_fn read_fn,
doom_write_fn write_fn,
doom_seek_fn seek_fn,
doom_tell_fn tell_fn,
doom_eof_fn eof_fn)
{
doom_open = open_fn;
doom_close = close_fn;
doom_read = read_fn;
doom_write = write_fn;
doom_seek = seek_fn;
doom_tell = tell_fn;
doom_eof = eof_fn;
}
void doom_set_gettime(doom_gettime_fn gettime_fn)
{
doom_gettime = gettime_fn;
}
void doom_set_exit(doom_exit_fn exit_fn)
{
doom_exit = exit_fn;
}
void doom_set_getenv(doom_getenv_fn getenv_fn)
{
doom_getenv = getenv_fn;
}
void doom_init(int argc, char** argv, int flags)
{
if (!doom_print) doom_print = doom_print_impl;
if (!doom_malloc) doom_malloc = doom_malloc_impl;
if (!doom_free) doom_free = doom_free_impl;
if (!doom_open) doom_open = doom_open_impl;
if (!doom_close) doom_close = doom_close_impl;
if (!doom_read) doom_read = doom_read_impl;
if (!doom_write) doom_write = doom_write_impl;
if (!doom_seek) doom_seek = doom_seek_impl;
if (!doom_tell) doom_tell = doom_tell_impl;
if (!doom_eof) doom_eof = doom_eof_impl;
if (!doom_gettime) doom_gettime = doom_gettime_impl;
if (!doom_exit) doom_exit = doom_exit_impl;
if (!doom_getenv) doom_getenv = doom_getenv_impl;
screen_buffer = doom_malloc(SCREENWIDTH * SCREENHEIGHT);
final_screen_buffer = doom_malloc(SCREENWIDTH * SCREENHEIGHT * 4);
last_update_time = I_GetTime();
myargc = argc;
myargv = argv;
doom_flags = flags;
D_DoomMain();
}
void doom_update()
{
int now = I_GetTime();
int delta_time = now - last_update_time;
while (delta_time-- > 0)
{
if (is_wiping_screen)
D_UpdateWipe();
else
D_DoomLoop();
}
last_update_time = now;
}
const unsigned char* doom_get_framebuffer(int channels)
{
int i, len;
doom_memcpy(screen_buffer, screens[0], SCREENWIDTH * SCREENHEIGHT);
extern doom_boolean menuactive;
extern gamestate_t gamestate;
extern doom_boolean automapactive;
extern int crosshair;
// Draw crosshair
if (crosshair &&
!menuactive &&
gamestate == GS_LEVEL &&
!automapactive)
{
int y;
extern int setblocks;
if (setblocks == 11) y = SCREENHEIGHT / 2 + 8;
else y = SCREENHEIGHT / 2 - 8;
for (i = 0; i < 2; ++i)
{
screen_buffer[SCREENWIDTH / 2 - 2 - i + y * SCREENWIDTH] = 4;
screen_buffer[SCREENWIDTH / 2 + 2 + i + y * SCREENWIDTH] = 4;
}
for (i = 0; i < 2; ++i)
{
screen_buffer[SCREENWIDTH / 2 + (y - 2 - i) * SCREENWIDTH] = 4;
screen_buffer[SCREENWIDTH / 2 + (y + 2 + i) * SCREENWIDTH] = 4;
}
}
if (channels == 1)
{
return screen_buffer;
}
else if (channels == 3)
{
for (i = 0, len = SCREENWIDTH * SCREENHEIGHT; i < len; ++i)
{
int k = i * 3;
int kpal = screen_buffer[i] * 3;
final_screen_buffer[k + 0] = screen_palette[kpal + 0];
final_screen_buffer[k + 1] = screen_palette[kpal + 1];
final_screen_buffer[k + 2] = screen_palette[kpal + 2];
}
return final_screen_buffer;
}
else if (channels == 4)
{
for (i = 0, len = SCREENWIDTH * SCREENHEIGHT; i < len; ++i)
{
int k = i * 4;
int kpal = screen_buffer[i] * 3;
final_screen_buffer[k + 0] = screen_palette[kpal + 0];
final_screen_buffer[k + 1] = screen_palette[kpal + 1];
final_screen_buffer[k + 2] = screen_palette[kpal + 2];
final_screen_buffer[k + 3] = 255;
}
return final_screen_buffer;
}
else
{
return 0;
}
}
unsigned long doom_tick_midi()
{
return I_TickSong();
}
short* doom_get_sound_buffer()
{
I_UpdateSound();
return mixbuffer;
}
void doom_key_down(doom_key_t key)
{
event_t event;
event.type = ev_keydown;
event.data1 = (int)key;
D_PostEvent(&event);
}
void doom_key_up(doom_key_t key)
{
event_t event;
event.type = ev_keyup;
event.data1 = (int)key;
D_PostEvent(&event);
}
void doom_button_down(doom_button_t button)
{
button_states[button] = 1;
event_t event;
event.type = ev_mouse;
event.data1 =
(button_states[0]) |
(button_states[1] ? 2 : 0) |
(button_states[2] ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
}
void doom_button_up(doom_button_t button)
{
button_states[button] = 0;
event_t event;
event.type = ev_mouse;
event.data1 =
(button_states[0]) |
(button_states[1] ? 2 : 0) |
(button_states[2] ? 4 : 0);
event.data1 =
event.data1
^ (button_states[0] ? 1 : 0)
^ (button_states[1] ? 2 : 0)
^ (button_states[2] ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
}
void doom_mouse_move(int delta_x, int delta_y)
{
event_t event;
event.type = ev_mouse;
event.data1 =
(button_states[0]) |
(button_states[1] ? 2 : 0) |
(button_states[2] ? 4 : 0);
event.data2 = delta_x;
event.data3 = -delta_y;
if (event.data2 || event.data3)
{
D_PostEvent(&event);
}
}

216
src/DOOM/DOOM.h Normal file
View File

@ -0,0 +1,216 @@
//-----------------------------------------------------------------------------
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//-----------------------------------------------------------------------------
/* Pure DOOM usage
Do this:
#define DOOM_IMPLEMENTATION
before you include this file in *one* C or C++ file to create the implementation.
// i.e. it should look like this:
#include ...
#include ...
#include ...
#define DOOM_IMPLEMENTATION
#include "PureDOOM.h"
*/
//-----------------------------------------------------------------------------
#ifndef __DOOM_H__
#define __DOOM_H__
// Sample rate of sound samples from doom
#define DOOM_SAMPLERATE 11025
// MIDI tick needs to be called 140 times per seconds
#define DOOM_MIDI_RATE 140
// Hide menu options. If for say your platform doesn't support mouse or
// MIDI playback, you can hide these settings from the menu.
#define DOOM_FLAG_HIDE_MOUSE_OPTIONS 1 // Remove mouse options from menu
#define DOOM_FLAG_HIDE_SOUND_OPTIONS 2 // Remove sound options from menu
#define DOOM_FLAG_HIDE_MUSIC_OPTIONS 4 // Remove music options from menu
// Darken background when menu is open, making it more readable. This
// uses a bit more CPU and redraws the HUD every frame
#define DOOM_FLAG_MENU_DARKEN_BG 8
#if __cplusplus
extern "C" {
#endif
typedef enum
{
DOOM_SEEK_CUR = 1,
DOOM_SEEK_END = 2,
DOOM_SEEK_SET = 0
} doom_seek_t;
typedef void(*doom_print_fn)(const char* str);
typedef void*(*doom_malloc_fn)(int size);
typedef void(*doom_free_fn)(void* ptr);
typedef void*(*doom_open_fn)(const char* filename, const char* mode);
typedef void(*doom_close_fn)(void* handle);
typedef int(*doom_read_fn)(void* handle, void *buf, int count);
typedef int(*doom_write_fn)(void* handle, const void *buf, int count);
typedef int(*doom_seek_fn)(void* handle, int offset, doom_seek_t origin);
typedef int(*doom_tell_fn)(void* handle);
typedef int(*doom_eof_fn)(void* handle);
typedef void(*doom_gettime_fn)(int* sec, int* usec);
typedef void(*doom_exit_fn)(int code);
typedef char*(*doom_getenv_fn)(const char* var);
// Doom key mapping
typedef enum
{
DOOM_KEY_UNKNOWN = -1,
DOOM_KEY_TAB = 9,
DOOM_KEY_ENTER = 13,
DOOM_KEY_ESCAPE = 27,
DOOM_KEY_SPACE = 32,
DOOM_KEY_APOSTROPHE = '\'',
DOOM_KEY_MULTIPLY = '*',
DOOM_KEY_COMMA = ',',
DOOM_KEY_MINUS = 0x2d,
DOOM_KEY_PERIOD = '.',
DOOM_KEY_SLASH = '/',
DOOM_KEY_0 = '0',
DOOM_KEY_1 = '1',
DOOM_KEY_2 = '2',
DOOM_KEY_3 = '3',
DOOM_KEY_4 = '4',
DOOM_KEY_5 = '5',
DOOM_KEY_6 = '6',
DOOM_KEY_7 = '7',
DOOM_KEY_8 = '8',
DOOM_KEY_9 = '9',
DOOM_KEY_SEMICOLON = ';',
DOOM_KEY_EQUALS = 0x3d,
DOOM_KEY_LEFT_BRACKET = '[',
DOOM_KEY_RIGHT_BRACKET = ']',
DOOM_KEY_A = 'a',
DOOM_KEY_B = 'b',
DOOM_KEY_C = 'c',
DOOM_KEY_D = 'd',
DOOM_KEY_E = 'e',
DOOM_KEY_F = 'f',
DOOM_KEY_G = 'g',
DOOM_KEY_H = 'h',
DOOM_KEY_I = 'i',
DOOM_KEY_J = 'j',
DOOM_KEY_K = 'k',
DOOM_KEY_L = 'l',
DOOM_KEY_M = 'm',
DOOM_KEY_N = 'n',
DOOM_KEY_O = 'o',
DOOM_KEY_P = 'p',
DOOM_KEY_Q = 'q',
DOOM_KEY_R = 'r',
DOOM_KEY_S = 's',
DOOM_KEY_T = 't',
DOOM_KEY_U = 'u',
DOOM_KEY_V = 'v',
DOOM_KEY_W = 'w',
DOOM_KEY_X = 'x',
DOOM_KEY_Y = 'y',
DOOM_KEY_Z = 'z',
DOOM_KEY_BACKSPACE = 127,
DOOM_KEY_CTRL = (0x80 + 0x1d), // Both left and right
DOOM_KEY_LEFT_ARROW = 0xac,
DOOM_KEY_UP_ARROW = 0xad,
DOOM_KEY_RIGHT_ARROW = 0xae,
DOOM_KEY_DOWN_ARROW = 0xaf,
DOOM_KEY_SHIFT = (0x80 + 0x36), // Both left and right
DOOM_KEY_ALT = (0x80 + 0x38), // Both left and right
DOOM_KEY_F1 = (0x80 + 0x3b),
DOOM_KEY_F2 = (0x80 + 0x3c),
DOOM_KEY_F3 = (0x80 + 0x3d),
DOOM_KEY_F4 = (0x80 + 0x3e),
DOOM_KEY_F5 = (0x80 + 0x3f),
DOOM_KEY_F6 = (0x80 + 0x40),
DOOM_KEY_F7 = (0x80 + 0x41),
DOOM_KEY_F8 = (0x80 + 0x42),
DOOM_KEY_F9 = (0x80 + 0x43),
DOOM_KEY_F10 = (0x80 + 0x44),
DOOM_KEY_F11 = (0x80 + 0x57),
DOOM_KEY_F12 = (0x80 + 0x58),
DOOM_KEY_PAUSE = 0xff
} doom_key_t;
// Mouse button mapping
typedef enum
{
DOOM_LEFT_BUTTON = 0,
DOOM_RIGHT_BUTTON = 1,
DOOM_MIDDLE_BUTTON = 2
} doom_button_t;
// For the software renderer. Default is 320x200
void doom_set_resolution(int width, int height);
// Set default configurations. Lets say, changing arrows to WASD as default controls
void doom_set_default_int(const char* name, int value);
void doom_set_default_string(const char* name, const char* value);
// set callbacks
void doom_set_print(doom_print_fn print_fn);
void doom_set_malloc(doom_malloc_fn malloc_fn, doom_free_fn free_fn);
void doom_set_file_io(doom_open_fn open_fn,
doom_close_fn close_fn,
doom_read_fn read_fn,
doom_write_fn write_fn,
doom_seek_fn seek_fn,
doom_tell_fn tell_fn,
doom_eof_fn eof_fn);
void doom_set_gettime(doom_gettime_fn gettime_fn);
void doom_set_exit(doom_exit_fn exit_fn);
void doom_set_getenv(doom_getenv_fn getenv_fn);
// Initializes DOOM and start things up. Call only call one
void doom_init(int argc, char** argv, int flags);
// Call this every frame
void doom_update();
// Channels: 1 = indexed, 3 = RGB, 4 = RGBA
const unsigned char* doom_get_framebuffer(int channels);
// It is always 2048 bytes in size
short* doom_get_sound_buffer();
// Call this 140 times per second. Or about every 7ms.
// Returns midi message. Keep calling it until it returns 0.
unsigned long doom_tick_midi();
// Events
void doom_key_down(doom_key_t key);
void doom_key_up(doom_key_t key);
void doom_button_down(doom_button_t button);
void doom_button_up(doom_button_t button);
void doom_mouse_move(int delta_x, int delta_y);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

112
src/DOOM/DOOMLIC.TXT Normal file
View File

@ -0,0 +1,112 @@
LIMITED USE SOFTWARE LICENSE AGREEMENT
This Limited Use Software License Agreement (the "Agreement")
is a legal agreement between you, the end-user, and Id Software, Inc.
("ID"). By downloading or purchasing the software material, which
includes source code (the "Source Code"), artwork data, music and
software tools (collectively, the "Software"), you are agreeing to
be bound by the terms of this Agreement. If you do not agree to the
terms of this Agreement, promptly destroy the Software you may have
downloaded or copied.
ID SOFTWARE LICENSE
1. Grant of License. ID grants to you the right to use the
Software. You have no ownership or proprietary rights in or to the
Software, or the Trademark. For purposes of this section, "use" means
loading the Software into RAM, as well as installation on a hard disk
or other storage device. The Software, together with any archive copy
thereof, shall be destroyed when no longer used in accordance with
this Agreement, or when the right to use the Software is terminated.
You agree that the Software will not be shipped, transferred or
exported into any country in violation of the U.S. Export
Administration Act (or any other law governing such matters) and that
you will not utilize, in any other manner, the Software in violation
of any applicable law.
2. Permitted Uses. For educational purposes only, you, the
end-user, may use portions of the Source Code, such as particular
routines, to develop your own software, but may not duplicate the
Source Code, except as noted in paragraph 4. The limited right
referenced in the preceding sentence is hereinafter referred to as
"Educational Use." By so exercising the Educational Use right you
shall not obtain any ownership, copyright, proprietary or other
interest in or to the Source Code, or any portion of the Source
Code. You may dispose of your own software in your sole discretion.
With the exception of the Educational Use right, you may not
otherwise use the Software, or an portion of the Software, which
includes the Source Code, for commercial gain.
3. Prohibited Uses: Under no circumstances shall you, the
end-user, be permitted, allowed or authorized to commercially exploit
the Software. Neither you nor anyone at your direction shall do any
of the following acts with regard to the Software, or any portion
thereof:
Rent;
Sell;
Lease;
Offer on a pay-per-play basis;
Distribute for money or any other consideration; or
In any other manner and through any medium whatsoever
commercially exploit or use for any commercial purpose.
Notwithstanding the foregoing prohibitions, you may commercially
exploit the software you develop by exercising the Educational Use
right, referenced in paragraph 2. hereinabove.
4. Copyright. The Software and all copyrights related thereto
(including all characters and other images generated by the Software
or depicted in the Software) are owned by ID and is protected by
United States copyright laws and international treaty provisions.
Id shall retain exclusive ownership and copyright in and to the
Software and all portions of the Software and you shall have no
ownership or other proprietary interest in such materials. You must
treat the Software like any other copyrighted material. You may not
otherwise reproduce, copy or disclose to others, in whole or in any
part, the Software. You may not copy the written materials
accompanying the Software. You agree to use your best efforts to
see that any user of the Software licensed hereunder complies with
this Agreement.
5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, BOTH EXPRESS
IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT
TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO
JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE
WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS.
THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS
WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES,
DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE
MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF
OF ID.
Exclusive Remedies. The Software is being offered to you
free of any charge. You agree that you have no remedy against ID, its
affiliates, contractors, suppliers, and agents for loss or damage
caused by any defect or failure in the Software regardless of the form
of action, whether in contract, tort, includinegligence, strict
liability or otherwise, with regard to the Software. This Agreement
shall be construed in accordance with and governed by the laws of the
State of Texas. Copyright and other proprietary matters will be
governed by United States laws and international treaties. IN ANY
CASE, ID SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST
SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER
SIMILAR DAMAGES ARISING FROM BREACH OF WARRANTY, BREACH OF CONTRACT,
NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
OTHER PARTY. Some jurisdictions do not allow the exclusion or
limitation of incidental or consequential damages, so the above
limitation or exclusion may not apply to you.

1319
src/DOOM/am_map.c Normal file

File diff suppressed because it is too large Load Diff

56
src/DOOM/am_map.h Normal file
View File

@ -0,0 +1,56 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// AutoMap module.
//
//-----------------------------------------------------------------------------
#ifndef __AMMAP_H__
#define __AMMAP_H__
#include "d_event.h"
// Used by ST StatusBar stuff.
#define AM_MSGHEADER (('a'<<24)+('m'<<16))
#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
// Called by main loop.
doom_boolean AM_Responder(event_t* ev);
// Called by main loop.
void AM_Ticker(void);
// Called by main loop,
// called instead of view drawer if automap active.
void AM_Drawer(void);
// Called to force the automap to quit
// if the level is completed while it is up.
void AM_Stop(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

699
src/DOOM/d_englsh.h Normal file
View File

@ -0,0 +1,699 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Printed strings for translation.
// English language support (default).
//
//-----------------------------------------------------------------------------
#ifndef __D_ENGLSH__
#define __D_ENGLSH__
//
// Printed strings for translation
//
//
// D_Main.C
//
#define D_DEVSTR "Development mode ON.\n"
#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n"
//
// M_Menu.C
//
#define PRESSKEY "press a key."
#define PRESSYN "press y or n."
#define QUITMSG "are you sure you want to\nquit this great game?"
#define LOADNET "you can't do load while in a net game!\n\n" PRESSKEY
#define QLOADNET "you can't quickload during a netgame!\n\n" PRESSKEY
#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n" PRESSKEY
#define SAVEDEAD "you can't save if you aren't playing!\n\n" PRESSKEY
#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n" PRESSYN
#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n" PRESSYN
#define QSPROMPT_1 "quicksave over your game named\n\n'"
#define QSPROMPT_2 "'?\n\n" PRESSYN
#define QLPROMPT_1 "do you want to quickload the game named\n\n'%s"
#define QLPROMPT_2 "'?\n\n" PRESSYN
#define NEWGAME \
"you can't start a new game\n"\
"while in a network game.\n\n" PRESSKEY
#define NIGHTMARE \
"are you sure? this skill level\n"\
"isn't even remotely fair.\n\n" PRESSYN
#define SWSTRING \
"this is the shareware version of doom.\n\n"\
"you need to order the entire trilogy.\n\n" PRESSKEY
#define MSGOFF "Messages OFF"
#define MSGON "Messages ON"
#define CROSSOFF "Crosshair OFF"
#define CROSSON "Crosshair ON"
#define ALWAYSRUNOFF "Always run OFF"
#define ALWAYSRUNON "Always run ON"
#define NETEND "you can't end a netgame!\n\n" PRESSKEY
#define ENDGAME "are you sure you want to end the game?\n\n" PRESSYN
#define DOSY "(press y to quit)"
#define DETAILHI "High detail"
#define DETAILLO "Low detail"
#define GAMMALVL0 "Gamma correction OFF"
#define GAMMALVL1 "Gamma correction level 1"
#define GAMMALVL2 "Gamma correction level 2"
#define GAMMALVL3 "Gamma correction level 3"
#define GAMMALVL4 "Gamma correction level 4"
#define EMPTYSTRING "empty slot"
//
// P_inter.C
//
#define GOTARMOR "Picked up the armor."
#define GOTMEGA "Picked up the MegaArmor!"
#define GOTHTHBONUS "Picked up a health bonus."
#define GOTARMBONUS "Picked up an armor bonus."
#define GOTSTIM "Picked up a stimpack."
#define GOTMEDINEED "Picked up a medikit that you REALLY need!"
#define GOTMEDIKIT "Picked up a medikit."
#define GOTSUPER "Supercharge!"
#define GOTBLUECARD "Picked up a blue keycard."
#define GOTYELWCARD "Picked up a yellow keycard."
#define GOTREDCARD "Picked up a red keycard."
#define GOTBLUESKUL "Picked up a blue skull key."
#define GOTYELWSKUL "Picked up a yellow skull key."
#define GOTREDSKULL "Picked up a red skull key."
#define GOTINVUL "Invulnerability!"
#define GOTBERSERK "Berserk!"
#define GOTINVIS "Partial Invisibility"
#define GOTSUIT "Radiation Shielding Suit"
#define GOTMAP "Computer Area Map"
#define GOTVISOR "Light Amplification Visor"
#define GOTMSPHERE "MegaSphere!"
#define GOTCLIP "Picked up a clip."
#define GOTCLIPBOX "Picked up a box of bullets."
#define GOTROCKET "Picked up a rocket."
#define GOTROCKBOX "Picked up a box of rockets."
#define GOTCELL "Picked up an energy cell."
#define GOTCELLBOX "Picked up an energy cell pack."
#define GOTSHELLS "Picked up 4 shotgun shells."
#define GOTSHELLBOX "Picked up a box of shotgun shells."
#define GOTBACKPACK "Picked up a backpack full of ammo!"
#define GOTBFG9000 "You got the BFG9000! Oh, yes."
#define GOTCHAINGUN "You got the chaingun!"
#define GOTCHAINSAW "A chainsaw! Find some meat!"
#define GOTLAUNCHER "You got the rocket launcher!"
#define GOTPLASMA "You got the plasma gun!"
#define GOTSHOTGUN "You got the shotgun!"
#define GOTSHOTGUN2 "You got the super shotgun!"
//
// P_Doors.C
//
#define PD_BLUEO "You need a blue key to activate this object"
#define PD_REDO "You need a red key to activate this object"
#define PD_YELLOWO "You need a yellow key to activate this object"
#define PD_BLUEK "You need a blue key to open this door"
#define PD_REDK "You need a red key to open this door"
#define PD_YELLOWK "You need a yellow key to open this door"
//
// G_game.C
//
#define GGSAVED "game saved."
//
// HU_stuff.C
//
#define HUSTR_MSGU "[Message unsent]"
#define HUSTR_E1M1 "E1M1: Hangar"
#define HUSTR_E1M2 "E1M2: Nuclear Plant"
#define HUSTR_E1M3 "E1M3: Toxin Refinery"
#define HUSTR_E1M4 "E1M4: Command Control"
#define HUSTR_E1M5 "E1M5: Phobos Lab"
#define HUSTR_E1M6 "E1M6: Central Processing"
#define HUSTR_E1M7 "E1M7: Computer Station"
#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
#define HUSTR_E1M9 "E1M9: Military Base"
#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
#define HUSTR_E2M2 "E2M2: Containment Area"
#define HUSTR_E2M3 "E2M3: Refinery"
#define HUSTR_E2M4 "E2M4: Deimos Lab"
#define HUSTR_E2M5 "E2M5: Command Center"
#define HUSTR_E2M6 "E2M6: Halls of the Damned"
#define HUSTR_E2M7 "E2M7: Spawning Vats"
#define HUSTR_E2M8 "E2M8: Tower of Babel"
#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
#define HUSTR_E3M1 "E3M1: Hell Keep"
#define HUSTR_E3M2 "E3M2: Slough of Despair"
#define HUSTR_E3M3 "E3M3: Pandemonium"
#define HUSTR_E3M4 "E3M4: House of Pain"
#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
#define HUSTR_E3M6 "E3M6: Mt. Erebus"
#define HUSTR_E3M7 "E3M7: Limbo"
#define HUSTR_E3M8 "E3M8: Dis"
#define HUSTR_E3M9 "E3M9: Warrens"
#define HUSTR_E4M1 "E4M1: Hell Beneath"
#define HUSTR_E4M2 "E4M2: Perfect Hatred"
#define HUSTR_E4M3 "E4M3: Sever The Wicked"
#define HUSTR_E4M4 "E4M4: Unruly Evil"
#define HUSTR_E4M5 "E4M5: They Will Repent"
#define HUSTR_E4M6 "E4M6: Against Thee Wickedly"
#define HUSTR_E4M7 "E4M7: And Hell Followed"
#define HUSTR_E4M8 "E4M8: Unto The Cruel"
#define HUSTR_E4M9 "E4M9: Fear"
#define HUSTR_1 "level 1: entryway"
#define HUSTR_2 "level 2: underhalls"
#define HUSTR_3 "level 3: the gantlet"
#define HUSTR_4 "level 4: the focus"
#define HUSTR_5 "level 5: the waste tunnels"
#define HUSTR_6 "level 6: the crusher"
#define HUSTR_7 "level 7: dead simple"
#define HUSTR_8 "level 8: tricks and traps"
#define HUSTR_9 "level 9: the pit"
#define HUSTR_10 "level 10: refueling base"
#define HUSTR_11 "level 11: 'o' of destruction!"
#define HUSTR_12 "level 12: the factory"
#define HUSTR_13 "level 13: downtown"
#define HUSTR_14 "level 14: the inmost dens"
#define HUSTR_15 "level 15: industrial zone"
#define HUSTR_16 "level 16: suburbs"
#define HUSTR_17 "level 17: tenements"
#define HUSTR_18 "level 18: the courtyard"
#define HUSTR_19 "level 19: the citadel"
#define HUSTR_20 "level 20: gotcha!"
#define HUSTR_21 "level 21: nirvana"
#define HUSTR_22 "level 22: the catacombs"
#define HUSTR_23 "level 23: barrels o' fun"
#define HUSTR_24 "level 24: the chasm"
#define HUSTR_25 "level 25: bloodfalls"
#define HUSTR_26 "level 26: the abandoned mines"
#define HUSTR_27 "level 27: monster condo"
#define HUSTR_28 "level 28: the spirit world"
#define HUSTR_29 "level 29: the living end"
#define HUSTR_30 "level 30: icon of sin"
#define HUSTR_31 "level 31: wolfenstein"
#define HUSTR_32 "level 32: grosse"
#define PHUSTR_1 "level 1: congo"
#define PHUSTR_2 "level 2: well of souls"
#define PHUSTR_3 "level 3: aztec"
#define PHUSTR_4 "level 4: caged"
#define PHUSTR_5 "level 5: ghost town"
#define PHUSTR_6 "level 6: baron's lair"
#define PHUSTR_7 "level 7: caughtyard"
#define PHUSTR_8 "level 8: realm"
#define PHUSTR_9 "level 9: abattoire"
#define PHUSTR_10 "level 10: onslaught"
#define PHUSTR_11 "level 11: hunted"
#define PHUSTR_12 "level 12: speed"
#define PHUSTR_13 "level 13: the crypt"
#define PHUSTR_14 "level 14: genesis"
#define PHUSTR_15 "level 15: the twilight"
#define PHUSTR_16 "level 16: the omen"
#define PHUSTR_17 "level 17: compound"
#define PHUSTR_18 "level 18: neurosphere"
#define PHUSTR_19 "level 19: nme"
#define PHUSTR_20 "level 20: the death domain"
#define PHUSTR_21 "level 21: slayer"
#define PHUSTR_22 "level 22: impossible mission"
#define PHUSTR_23 "level 23: tombstone"
#define PHUSTR_24 "level 24: the final frontier"
#define PHUSTR_25 "level 25: the temple of darkness"
#define PHUSTR_26 "level 26: bunker"
#define PHUSTR_27 "level 27: anti-christ"
#define PHUSTR_28 "level 28: the sewers"
#define PHUSTR_29 "level 29: odyssey of noises"
#define PHUSTR_30 "level 30: the gateway of hell"
#define PHUSTR_31 "level 31: cyberden"
#define PHUSTR_32 "level 32: go 2 it"
#define THUSTR_1 "level 1: system control"
#define THUSTR_2 "level 2: human bbq"
#define THUSTR_3 "level 3: power control"
#define THUSTR_4 "level 4: wormhole"
#define THUSTR_5 "level 5: hanger"
#define THUSTR_6 "level 6: open season"
#define THUSTR_7 "level 7: prison"
#define THUSTR_8 "level 8: metal"
#define THUSTR_9 "level 9: stronghold"
#define THUSTR_10 "level 10: redemption"
#define THUSTR_11 "level 11: storage facility"
#define THUSTR_12 "level 12: crater"
#define THUSTR_13 "level 13: nukage processing"
#define THUSTR_14 "level 14: steel works"
#define THUSTR_15 "level 15: dead zone"
#define THUSTR_16 "level 16: deepest reaches"
#define THUSTR_17 "level 17: processing area"
#define THUSTR_18 "level 18: mill"
#define THUSTR_19 "level 19: shipping/respawning"
#define THUSTR_20 "level 20: central processing"
#define THUSTR_21 "level 21: administration center"
#define THUSTR_22 "level 22: habitat"
#define THUSTR_23 "level 23: lunar mining project"
#define THUSTR_24 "level 24: quarry"
#define THUSTR_25 "level 25: baron's den"
#define THUSTR_26 "level 26: ballistyx"
#define THUSTR_27 "level 27: mount pain"
#define THUSTR_28 "level 28: heck"
#define THUSTR_29 "level 29: river styx"
#define THUSTR_30 "level 30: last call"
#define THUSTR_31 "level 31: pharaoh"
#define THUSTR_32 "level 32: caribbean"
#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
#define HUSTR_CHATMACRO2 "I'm OK."
#define HUSTR_CHATMACRO3 "I'm not looking too good!"
#define HUSTR_CHATMACRO4 "Help!"
#define HUSTR_CHATMACRO5 "You suck!"
#define HUSTR_CHATMACRO6 "Next time, scumbag..."
#define HUSTR_CHATMACRO7 "Come here!"
#define HUSTR_CHATMACRO8 "I'll take care of it."
#define HUSTR_CHATMACRO9 "Yes"
#define HUSTR_CHATMACRO0 "No"
#define HUSTR_TALKTOSELF1 "You mumble to yourself"
#define HUSTR_TALKTOSELF2 "Who's there?"
#define HUSTR_TALKTOSELF3 "You scare yourself"
#define HUSTR_TALKTOSELF4 "You start to rave"
#define HUSTR_TALKTOSELF5 "You've lost it..."
#define HUSTR_MESSAGESENT "[Message Sent]"
// The following should NOT be changed unless it seems
// just AWFULLY necessary
#define HUSTR_PLRGREEN "Green: "
#define HUSTR_PLRINDIGO "Indigo: "
#define HUSTR_PLRBROWN "Brown: "
#define HUSTR_PLRRED "Red: "
#define HUSTR_KEYGREEN 'g'
#define HUSTR_KEYINDIGO 'i'
#define HUSTR_KEYBROWN 'b'
#define HUSTR_KEYRED 'r'
//
// AM_map.C
//
#define AMSTR_FOLLOWON "Follow Mode ON"
#define AMSTR_FOLLOWOFF "Follow Mode OFF"
#define AMSTR_GRIDON "Grid ON"
#define AMSTR_GRIDOFF "Grid OFF"
#define AMSTR_MARKEDSPOT "Marked Spot"
#define AMSTR_MARKSCLEARED "All Marks Cleared"
//
// ST_stuff.C
//
#define STSTR_MUS "Music Change"
#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
#define STSTR_DQDON "Degreelessness Mode On"
#define STSTR_DQDOFF "Degreelessness Mode Off"
#define STSTR_KFAADDED "Very Happy Ammo Added"
#define STSTR_FAADDED "Ammo (no keys) Added"
#define STSTR_NCON "No Clipping Mode ON"
#define STSTR_NCOFF "No Clipping Mode OFF"
#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
#define STSTR_BEHOLDX "Power-up Toggled"
#define STSTR_CHOPPERS "... doesn't suck - GM"
#define STSTR_CLEV "Changing Level..."
//
// F_Finale.C
//
#define E1TEXT \
"Once you beat the big badasses and\n"\
"clean out the moon base you're supposed\n"\
"to win, aren't you? Aren't you? Where's\n"\
"your fat reward and ticket home? What\n"\
"the hell is this? It's not supposed to\n"\
"end this way!\n"\
"\n" \
"It stinks like rotten meat, but looks\n"\
"like the lost Deimos base. Looks like\n"\
"you're stuck on The Shores of Hell.\n"\
"The only way out is through.\n"\
"\n"\
"To continue the DOOM experience, play\n"\
"The Shores of Hell and its amazing\n"\
"sequel, Inferno!\n"
#define E2TEXT \
"You've done it! The hideous cyber-\n"\
"demon lord that ruled the lost Deimos\n"\
"moon base has been slain and you\n"\
"are triumphant! But ... where are\n"\
"you? You clamber to the edge of the\n"\
"moon and look down to see the awful\n"\
"truth.\n" \
"\n"\
"Deimos floats above Hell itself!\n"\
"You've never heard of anyone escaping\n"\
"from Hell, but you'll make the bastards\n"\
"sorry they ever heard of you! Quickly,\n"\
"you rappel down to the surface of\n"\
"Hell.\n"\
"\n" \
"Now, it's on to the final chapter of\n"\
"DOOM! -- Inferno."
#define E3TEXT \
"The loathsome spiderdemon that\n"\
"masterminded the invasion of the moon\n"\
"bases and caused so much death has had\n"\
"its ass kicked for all time.\n"\
"\n"\
"A hidden doorway opens and you enter.\n"\
"You've proven too tough for Hell to\n"\
"contain, and now Hell at last plays\n"\
"fair -- for you emerge from the door\n"\
"to see the green fields of Earth!\n"\
"Home at last.\n" \
"\n"\
"You wonder what's been happening on\n"\
"Earth while you were battling evil\n"\
"unleashed. It's good that no Hell-\n"\
"spawn could have come through that\n"\
"door with you ..."
#define E4TEXT \
"the spider mastermind must have sent forth\n"\
"its legions of hellspawn before your\n"\
"final confrontation with that terrible\n"\
"beast from hell. but you stepped forward\n"\
"and brought forth eternal damnation and\n"\
"suffering upon the horde as a true hero\n"\
"would in the face of something so evil.\n"\
"\n"\
"besides, someone was gonna pay for what\n"\
"happened to daisy, your pet rabbit.\n"\
"\n"\
"but now, you see spread before you more\n"\
"potential pain and gibbitude as a nation\n"\
"of demons run amok among our cities.\n"\
"\n"\
"next stop, hell on earth!"
// after level 6, put this:
#define C1TEXT \
"YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \
"STARPORT. BUT SOMETHING IS WRONG. THE\n" \
"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \
"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \
"IS BEING SUBVERTED BY THEIR PRESENCE.\n" \
"\n"\
"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \
"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \
"YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \
"OF THE STARBASE AND FIND THE CONTROLLING\n" \
"SWITCH WHICH HOLDS EARTH'S POPULATION\n" \
"HOSTAGE."
// After level 11, put this:
#define C2TEXT \
"YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \
"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\
"THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\
"HUMAN LEFT ON THE FACE OF THE PLANET.\n"\
"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\
"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\
"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\
"THAT YOU HAVE SAVED YOUR SPECIES.\n"\
"\n"\
"BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\
"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\
"THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\
"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\
"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\
"YOUR OWN HOME CITY, NOT FAR FROM THE\n"\
"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\
"UP AND RETURN TO THE FRAY."
// After level 20, put this:
#define C3TEXT \
"YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\
"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\
"YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\
"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\
"TEETH AND PLUNGE THROUGH IT.\n"\
"\n"\
"THERE MUST BE A WAY TO CLOSE IT ON THE\n"\
"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\
"GOT TO GO THROUGH HELL TO GET TO IT?"
// After level 29, put this:
#define C4TEXT \
"THE HORRENDOUS VISAGE OF THE BIGGEST\n"\
"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\
"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\
"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\
"UP AND DIES, ITS THRASHING LIMBS\n"\
"DEVASTATING UNTOLD MILES OF HELL'S\n"\
"SURFACE.\n"\
"\n"\
"YOU'VE DONE IT. THE INVASION IS OVER.\n"\
"EARTH IS SAVED. HELL IS A WRECK. YOU\n"\
"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\
"DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\
"FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\
"HOME. REBUILDING EARTH OUGHT TO BE A\n"\
"LOT MORE FUN THAN RUINING IT WAS.\n"
// Before level 31, put this:
#define C5TEXT \
"CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\
"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\
"HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\
"WHO THE INMATES OF THIS CORNER OF HELL\n"\
"WILL BE."
// Before level 32, put this:
#define C6TEXT \
"CONGRATULATIONS, YOU'VE FOUND THE\n"\
"SUPER SECRET LEVEL! YOU'D BETTER\n"\
"BLAZE THROUGH THIS ONE!\n"
// after map 06
#define P1TEXT \
"You gloat over the steaming carcass of the\n"\
"Guardian. With its death, you've wrested\n"\
"the Accelerator from the stinking claws\n"\
"of Hell. You relax and glance around the\n"\
"room. Damn! There was supposed to be at\n"\
"least one working prototype, but you can't\n"\
"see it. The demons must have taken it.\n"\
"\n"\
"You must find the prototype, or all your\n"\
"struggles will have been wasted. Keep\n"\
"moving, keep fighting, keep killing.\n"\
"Oh yes, keep living, too."
// after map 11
#define P2TEXT \
"Even the deadly Arch-Vile labyrinth could\n"\
"not stop you, and you've gotten to the\n"\
"prototype Accelerator which is soon\n"\
"efficiently and permanently deactivated.\n"\
"\n"\
"You're good at that kind of thing."
// after map 20
#define P3TEXT \
"You've bashed and battered your way into\n"\
"the heart of the devil-hive. Time for a\n"\
"Search-and-Destroy mission, aimed at the\n"\
"Gatekeeper, whose foul offspring is\n"\
"cascading to Earth. Yeah, he's bad. But\n"\
"you know who's worse!\n"\
"\n"\
"Grinning evilly, you check your gear, and\n"\
"get ready to give the bastard a little Hell\n"\
"of your own making!"
// after map 30
#define P4TEXT \
"The Gatekeeper's evil face is splattered\n"\
"all over the place. As its tattered corpse\n"\
"collapses, an inverted Gate forms and\n"\
"sucks down the shards of the last\n"\
"prototype Accelerator, not to mention the\n"\
"few remaining demons. You're done. Hell\n"\
"has gone back to pounding bad dead folks \n"\
"instead of good live ones. Remember to\n"\
"tell your grandkids to put a rocket\n"\
"launcher in your coffin. If you go to Hell\n"\
"when you die, you'll need it for some\n"\
"final cleaning-up ..."
// before map 31
#define P5TEXT \
"You've found the second-hardest level we\n"\
"got. Hope you have a saved game a level or\n"\
"two previous. If not, be prepared to die\n"\
"aplenty. For master marines only."
// before map 32
#define P6TEXT \
"Betcha wondered just what WAS the hardest\n"\
"level we had ready for ya? Now you know.\n"\
"No one gets out alive."
#define T1TEXT \
"You've fought your way out of the infested\n"\
"experimental labs. It seems that UAC has\n"\
"once again gulped it down. With their\n"\
"high turnover, it must be hard for poor\n"\
"old UAC to buy corporate health insurance\n"\
"nowadays..\n"\
"\n"\
"Ahead lies the military complex, now\n"\
"swarming with diseased horrors hot to get\n"\
"their teeth into you. With luck, the\n"\
"complex still has some warlike ordnance\n"\
"laying around."
#define T2TEXT \
"You hear the grinding of heavy machinery\n"\
"ahead. You sure hope they're not stamping\n"\
"out new hellspawn, but you're ready to\n"\
"ream out a whole herd if you have to.\n"\
"They might be planning a blood feast, but\n"\
"you feel about as mean as two thousand\n"\
"maniacs packed into one mad killer.\n"\
"\n"\
"You don't plan to go down easy."
#define T3TEXT \
"The vista opening ahead looks real damn\n"\
"familiar. Smells familiar, too -- like\n"\
"fried excrement. You didn't like this\n"\
"place before, and you sure as hell ain't\n"\
"planning to like it now. The more you\n"\
"brood on it, the madder you get.\n"\
"Hefting your gun, an evil grin trickles\n"\
"onto your face. Time to take some names."
#define T4TEXT \
"Suddenly, all is silent, from one horizon\n"\
"to the other. The agonizing echo of Hell\n"\
"fades away, the nightmare sky turns to\n"\
"blue, the heaps of monster corpses start \n"\
"to evaporate along with the evil stench \n"\
"that filled the air. Jeeze, maybe you've\n"\
"done it. Have you really won?\n"\
"\n"\
"Something rumbles in the distance.\n"\
"A blue light begins to glow inside the\n"\
"ruined skull of the demon-spitter."
#define T5TEXT \
"What now? Looks totally different. Kind\n"\
"of like King Tut's condo. Well,\n"\
"whatever's here can't be any worse\n"\
"than usual. Can it? Or maybe it's best\n"\
"to let sleeping gods lie.."
#define T6TEXT \
"Time for a vacation. You've burst the\n"\
"bowels of hell and by golly you're ready\n"\
"for a break. You mutter to yourself,\n"\
"Maybe someone else can kick Hell's ass\n"\
"next time around. Ahead lies a quiet town,\n"\
"with peaceful flowing water, quaint\n"\
"buildings, and presumably no Hellspawn.\n"\
"\n"\
"As you step off the transport, you hear\n"\
"the stomp of a cyberdemon's iron shoe."
//
// Character cast strings F_FINALE.C
//
#define CC_ZOMBIE "ZOMBIEMAN"
#define CC_SHOTGUN "SHOTGUN GUY"
#define CC_HEAVY "HEAVY WEAPON DUDE"
#define CC_IMP "IMP"
#define CC_DEMON "DEMON"
#define CC_LOST "LOST SOUL"
#define CC_CACO "CACODEMON"
#define CC_HELL "HELL KNIGHT"
#define CC_BARON "BARON OF HELL"
#define CC_ARACH "ARACHNOTRON"
#define CC_PAIN "PAIN ELEMENTAL"
#define CC_REVEN "REVENANT"
#define CC_MANCU "MANCUBUS"
#define CC_ARCH "ARCH-VILE"
#define CC_SPIDER "THE SPIDER MASTERMIND"
#define CC_CYBER "THE CYBERDEMON"
#define CC_HERO "OUR HERO"
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

119
src/DOOM/d_event.h Normal file
View File

@ -0,0 +1,119 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __D_EVENT__
#define __D_EVENT__
#include "doomtype.h"
//
// Event handling.
//
// Input event types.
typedef enum
{
ev_keydown,
ev_keyup,
ev_mouse,
ev_joystick
} evtype_t;
// Event structure.
typedef struct
{
evtype_t type;
int data1; // keys / mouse/joystick buttons
int data2; // mouse/joystick x move
int data3; // mouse/joystick y move
} event_t;
typedef enum
{
ga_nothing,
ga_loadlevel,
ga_newgame,
ga_loadgame,
ga_savegame,
ga_playdemo,
ga_completed,
ga_victory,
ga_worlddone,
ga_screenshot
} gameaction_t;
//
// Button/action code definitions.
//
typedef enum
{
// Press "Fire".
BT_ATTACK = 1,
// Use button, to open doors, activate switches.
BT_USE = 2,
// Flag: game events, not really buttons.
BT_SPECIAL = 128,
BT_SPECIALMASK = 3,
// Flag, weapon change pending.
// If true, the next 3 bits hold weapon num.
BT_CHANGE = 4,
// The 3bit weapon mask and shift, convenience.
BT_WEAPONMASK = (8 + 16 + 32),
BT_WEAPONSHIFT = 3,
// Pause the game.
BTS_PAUSE = 1,
// Save the game at each console.
BTS_SAVEGAME = 2,
// Savegame slot numbers
// occupy the second byte of buttons.
BTS_SAVEMASK = (4 + 8 + 16),
BTS_SAVESHIFT = 2,
} buttoncode_t;
//
// GLOBAL VARIABLES
//
#define MAXEVENTS (64 * 64) // [pd] Crank up the number because we pump them faster
extern event_t events[MAXEVENTS];
extern int eventhead;
extern int eventtail;
extern gameaction_t gameaction;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

433
src/DOOM/d_french.h Normal file
View File

@ -0,0 +1,433 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Printed strings, french translation.
//
//-----------------------------------------------------------------------------
#ifndef __D_FRENCH__
#define __D_FRENCH__
//
// D_Main.C
//
#define D_DEVSTR "MODE DEVELOPPEMENT ON.\n"
#define D_CDROM "VERSION CD-ROM: DEFAULT.CFG DANS C:\\DOOMDATA\n"
//
// M_Menu.C
//
#define PRESSKEY "APPUYEZ SUR UNE TOUCHE."
#define PRESSYN "APPUYEZ SUR Y OU N"
#define QUITMSG "VOUS VOULEZ VRAIMENT\nQUITTER CE SUPER JEU?"
#define LOADNET "VOUS NE POUVEZ PAS CHARGER\nUN JEU EN RESEAU!\n\n"PRESSKEY
#define QLOADNET "CHARGEMENT RAPIDE INTERDIT EN RESEAU!\n\n"PRESSKEY
#define QSAVESPOT "VOUS N'AVEZ PAS CHOISI UN EMPLACEMENT!\n\n"PRESSKEY
#define SAVEDEAD "VOUS NE POUVEZ PAS SAUVER SI VOUS NE JOUEZ "\
"PAS!\n\n"PRESSKEY
#define QSPROMPT "SAUVEGARDE RAPIDE DANS LE FICHIER \n\n'%s'?\n\n"PRESSYN
#define QLPROMPT "VOULEZ-VOUS CHARGER LA SAUVEGARDE"\
"\n\n'%s'?\n\n"PRESSYN
#define NEWGAME "VOUS NE POUVEZ PAS LANCER\n"\
"UN NOUVEAU JEU SUR RESEAU.\n\n"PRESSKEY
#define NIGHTMARE "VOUS CONFIRMEZ? CE NIVEAU EST\n"\
"VRAIMENT IMPITOYABLE!n"PRESSYN
#define SWSTRING "CECI EST UNE VERSION SHAREWARE DE DOOM.\n\n"\
"VOUS DEVRIEZ COMMANDER LA TRILOGIE COMPLETE.\n\n"PRESSKEY
#define MSGOFF "MESSAGES OFF"
#define MSGON "MESSAGES ON"
#define NETEND "VOUS NE POUVEZ PAS METTRE FIN A UN JEU SUR "\
"RESEAU!\n\n"PRESSKEY
#define ENDGAME "VOUS VOULEZ VRAIMENT METTRE FIN AU JEU?\n\n"PRESSYN
#define DOSY "(APPUYEZ SUR Y POUR REVENIR AU OS.)"
#define DETAILHI "GRAPHISMES MAXIMUM "
#define DETAILLO "GRAPHISMES MINIMUM "
#define GAMMALVL0 "CORRECTION GAMMA OFF"
#define GAMMALVL1 "CORRECTION GAMMA NIVEAU 1"
#define GAMMALVL2 "CORRECTION GAMMA NIVEAU 2"
#define GAMMALVL3 "CORRECTION GAMMA NIVEAU 3"
#define GAMMALVL4 "CORRECTION GAMMA NIVEAU 4"
#define EMPTYSTRING "EMPLACEMENT VIDE"
//
// P_inter.C
//
#define GOTARMOR "ARMURE RECUPEREE."
#define GOTMEGA "MEGA-ARMURE RECUPEREE!"
#define GOTHTHBONUS "BONUS DE SANTE RECUPERE."
#define GOTARMBONUS "BONUS D'ARMURE RECUPERE."
#define GOTSTIM "STIMPACK RECUPERE."
#define GOTMEDINEED "MEDIKIT RECUPERE. VOUS EN AVEZ VRAIMENT BESOIN!"
#define GOTMEDIKIT "MEDIKIT RECUPERE."
#define GOTSUPER "SUPERCHARGE!"
#define GOTBLUECARD "CARTE MAGNETIQUE BLEUE RECUPEREE."
#define GOTYELWCARD "CARTE MAGNETIQUE JAUNE RECUPEREE."
#define GOTREDCARD "CARTE MAGNETIQUE ROUGE RECUPEREE."
#define GOTBLUESKUL "CLEF CRANE BLEUE RECUPEREE."
#define GOTYELWSKUL "CLEF CRANE JAUNE RECUPEREE."
#define GOTREDSKULL "CLEF CRANE ROUGE RECUPEREE."
#define GOTINVUL "INVULNERABILITE!"
#define GOTBERSERK "BERSERK!"
#define GOTINVIS "INVISIBILITE PARTIELLE "
#define GOTSUIT "COMBINAISON ANTI-RADIATIONS "
#define GOTMAP "CARTE INFORMATIQUE "
#define GOTVISOR "VISEUR A AMPLIFICATION DE LUMIERE "
#define GOTMSPHERE "MEGASPHERE!"
#define GOTCLIP "CHARGEUR RECUPERE."
#define GOTCLIPBOX "BOITE DE BALLES RECUPEREE."
#define GOTROCKET "ROQUETTE RECUPEREE."
#define GOTROCKBOX "CAISSE DE ROQUETTES RECUPEREE."
#define GOTCELL "CELLULE D'ENERGIE RECUPEREE."
#define GOTCELLBOX "PACK DE CELLULES D'ENERGIE RECUPERE."
#define GOTSHELLS "4 CARTOUCHES RECUPEREES."
#define GOTSHELLBOX "BOITE DE CARTOUCHES RECUPEREE."
#define GOTBACKPACK "SAC PLEIN DE MUNITIONS RECUPERE!"
#define GOTBFG9000 "VOUS AVEZ UN BFG9000! OH, OUI!"
#define GOTCHAINGUN "VOUS AVEZ LA MITRAILLEUSE!"
#define GOTCHAINSAW "UNE TRONCONNEUSE!"
#define GOTLAUNCHER "VOUS AVEZ UN LANCE-ROQUETTES!"
#define GOTPLASMA "VOUS AVEZ UN FUSIL A PLASMA!"
#define GOTSHOTGUN "VOUS AVEZ UN FUSIL!"
#define GOTSHOTGUN2 "VOUS AVEZ UN SUPER FUSIL!"
//
// P_Doors.C
//
#define PD_BLUEO "IL VOUS FAUT UNE CLEF BLEUE"
#define PD_REDO "IL VOUS FAUT UNE CLEF ROUGE"
#define PD_YELLOWO "IL VOUS FAUT UNE CLEF JAUNE"
#define PD_BLUEK PD_BLUEO
#define PD_REDK PD_REDO
#define PD_YELLOWK PD_YELLOWO
//
// G_game.C
//
#define GGSAVED "JEU SAUVEGARDE."
//
// HU_stuff.C
//
#define HUSTR_MSGU "[MESSAGE NON ENVOYE]"
#define HUSTR_E1M1 "E1M1: HANGAR"
#define HUSTR_E1M2 "E1M2: USINE NUCLEAIRE "
#define HUSTR_E1M3 "E1M3: RAFFINERIE DE TOXINES "
#define HUSTR_E1M4 "E1M4: CENTRE DE CONTROLE "
#define HUSTR_E1M5 "E1M5: LABORATOIRE PHOBOS "
#define HUSTR_E1M6 "E1M6: TRAITEMENT CENTRAL "
#define HUSTR_E1M7 "E1M7: CENTRE INFORMATIQUE "
#define HUSTR_E1M8 "E1M8: ANOMALIE PHOBOS "
#define HUSTR_E1M9 "E1M9: BASE MILITAIRE "
#define HUSTR_E2M1 "E2M1: ANOMALIE DEIMOS "
#define HUSTR_E2M2 "E2M2: ZONE DE CONFINEMENT "
#define HUSTR_E2M3 "E2M3: RAFFINERIE"
#define HUSTR_E2M4 "E2M4: LABORATOIRE DEIMOS "
#define HUSTR_E2M5 "E2M5: CENTRE DE CONTROLE "
#define HUSTR_E2M6 "E2M6: HALLS DES DAMNES "
#define HUSTR_E2M7 "E2M7: CUVES DE REPRODUCTION "
#define HUSTR_E2M8 "E2M8: TOUR DE BABEL "
#define HUSTR_E2M9 "E2M9: FORTERESSE DU MYSTERE "
#define HUSTR_E3M1 "E3M1: DONJON DE L'ENFER "
#define HUSTR_E3M2 "E3M2: BOURBIER DU DESESPOIR "
#define HUSTR_E3M3 "E3M3: PANDEMONIUM"
#define HUSTR_E3M4 "E3M4: MAISON DE LA DOULEUR "
#define HUSTR_E3M5 "E3M5: CATHEDRALE PROFANE "
#define HUSTR_E3M6 "E3M6: MONT EREBUS"
#define HUSTR_E3M7 "E3M7: LIMBES"
#define HUSTR_E3M8 "E3M8: DIS"
#define HUSTR_E3M9 "E3M9: CLAPIERS"
#define HUSTR_1 "NIVEAU 1: ENTREE "
#define HUSTR_2 "NIVEAU 2: HALLS SOUTERRAINS "
#define HUSTR_3 "NIVEAU 3: LE FEU NOURRI "
#define HUSTR_4 "NIVEAU 4: LE FOYER "
#define HUSTR_5 "NIVEAU 5: LES EGOUTS "
#define HUSTR_6 "NIVEAU 6: LE BROYEUR "
#define HUSTR_7 "NIVEAU 7: L'HERBE DE LA MORT"
#define HUSTR_8 "NIVEAU 8: RUSES ET PIEGES "
#define HUSTR_9 "NIVEAU 9: LE PUITS "
#define HUSTR_10 "NIVEAU 10: BASE DE RAVITAILLEMENT "
#define HUSTR_11 "NIVEAU 11: LE CERCLE DE LA MORT!"
#define HUSTR_12 "NIVEAU 12: L'USINE "
#define HUSTR_13 "NIVEAU 13: LE CENTRE VILLE"
#define HUSTR_14 "NIVEAU 14: LES ANTRES PROFONDES "
#define HUSTR_15 "NIVEAU 15: LA ZONE INDUSTRIELLE "
#define HUSTR_16 "NIVEAU 16: LA BANLIEUE"
#define HUSTR_17 "NIVEAU 17: LES IMMEUBLES"
#define HUSTR_18 "NIVEAU 18: LA COUR "
#define HUSTR_19 "NIVEAU 19: LA CITADELLE "
#define HUSTR_20 "NIVEAU 20: JE T'AI EU!"
#define HUSTR_21 "NIVEAU 21: LE NIRVANA"
#define HUSTR_22 "NIVEAU 22: LES CATACOMBES "
#define HUSTR_23 "NIVEAU 23: LA GRANDE FETE "
#define HUSTR_24 "NIVEAU 24: LE GOUFFRE "
#define HUSTR_25 "NIVEAU 25: LES CHUTES DE SANG"
#define HUSTR_26 "NIVEAU 26: LES MINES ABANDONNEES "
#define HUSTR_27 "NIVEAU 27: CHEZ LES MONSTRES "
#define HUSTR_28 "NIVEAU 28: LE MONDE DE L'ESPRIT "
#define HUSTR_29 "NIVEAU 29: LA LIMITE "
#define HUSTR_30 "NIVEAU 30: L'ICONE DU PECHE "
#define HUSTR_31 "NIVEAU 31: WOLFENSTEIN"
#define HUSTR_32 "NIVEAU 32: LE MASSACRE"
#define HUSTR_CHATMACRO1 "JE SUIS PRET A LEUR EN FAIRE BAVER!"
#define HUSTR_CHATMACRO2 "JE VAIS BIEN."
#define HUSTR_CHATMACRO3 "JE N'AI PAS L'AIR EN FORME!"
#define HUSTR_CHATMACRO4 "AU SECOURS!"
#define HUSTR_CHATMACRO5 "TU CRAINS!"
#define HUSTR_CHATMACRO6 "LA PROCHAINE FOIS, MINABLE..."
#define HUSTR_CHATMACRO7 "VIENS ICI!"
#define HUSTR_CHATMACRO8 "JE VAIS M'EN OCCUPER."
#define HUSTR_CHATMACRO9 "OUI"
#define HUSTR_CHATMACRO0 "NON"
#define HUSTR_TALKTOSELF1 "VOUS PARLEZ TOUT SEUL "
#define HUSTR_TALKTOSELF2 "QUI EST LA?"
#define HUSTR_TALKTOSELF3 "VOUS VOUS FAITES PEUR "
#define HUSTR_TALKTOSELF4 "VOUS COMMENCEZ A DELIRER "
#define HUSTR_TALKTOSELF5 "VOUS ETES LARGUE..."
#define HUSTR_MESSAGESENT "[MESSAGE ENVOYE]"
// The following should NOT be changed unless it seems
// just AWFULLY necessary
#define HUSTR_PLRGREEN "VERT: "
#define HUSTR_PLRINDIGO "INDIGO: "
#define HUSTR_PLRBROWN "BRUN: "
#define HUSTR_PLRRED "ROUGE: "
#define HUSTR_KEYGREEN 'g' // french key should be "V"
#define HUSTR_KEYINDIGO 'i'
#define HUSTR_KEYBROWN 'b'
#define HUSTR_KEYRED 'r'
//
// AM_map.C
//
#define AMSTR_FOLLOWON "MODE POURSUITE ON"
#define AMSTR_FOLLOWOFF "MODE POURSUITE OFF"
#define AMSTR_GRIDON "GRILLE ON"
#define AMSTR_GRIDOFF "GRILLE OFF"
#define AMSTR_MARKEDSPOT "REPERE MARQUE "
#define AMSTR_MARKSCLEARED "REPERES EFFACES "
//
// ST_stuff.C
//
#define STSTR_MUS "CHANGEMENT DE MUSIQUE "
#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
#define STSTR_DQDON "INVULNERABILITE ON "
#define STSTR_DQDOFF "INVULNERABILITE OFF"
#define STSTR_KFAADDED "ARMEMENT MAXIMUM! "
#define STSTR_FAADDED "ARMES (SAUF CLEFS) AJOUTEES"
#define STSTR_NCON "BARRIERES ON"
#define STSTR_NCOFF "BARRIERES OFF"
#define STSTR_BEHOLD " inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
#define STSTR_BEHOLDX "AMELIORATION ACTIVEE"
#define STSTR_CHOPPERS "... DOESN'T SUCK - GM"
#define STSTR_CLEV "CHANGEMENT DE NIVEAU..."
//
// F_Finale.C
//
#define E1TEXT "APRES AVOIR VAINCU LES GROS MECHANTS\n"\
"ET NETTOYE LA BASE LUNAIRE, VOUS AVEZ\n"\
"GAGNE, NON? PAS VRAI? OU EST DONC VOTRE\n"\
" RECOMPENSE ET VOTRE BILLET DE\n"\
"RETOUR? QU'EST-QUE CA VEUT DIRE?CE"\
"N'EST PAS LA FIN ESPEREE!\n"\
"\n" \
"CA SENT LA VIANDE PUTREFIEE, MAIS\n"\
"ON DIRAIT LA BASE DEIMOS. VOUS ETES\n"\
"APPAREMMENT BLOQUE AUX PORTES DE L'ENFER.\n"\
"LA SEULE ISSUE EST DE L'AUTRE COTE.\n"\
"\n"\
"POUR VIVRE LA SUITE DE DOOM, JOUEZ\n"\
"A 'AUX PORTES DE L'ENFER' ET A\n"\
"L'EPISODE SUIVANT, 'L'ENFER'!\n"
#define E2TEXT "VOUS AVEZ REUSSI. L'INFAME DEMON\n"\
"QUI CONTROLAIT LA BASE LUNAIRE DE\n"\
"DEIMOS EST MORT, ET VOUS AVEZ\n"\
"TRIOMPHE! MAIS... OU ETES-VOUS?\n"\
"VOUS GRIMPEZ JUSQU'AU BORD DE LA\n"\
"LUNE ET VOUS DECOUVREZ L'ATROCE\n"\
"VERITE.\n" \
"\n"\
"DEIMOS EST AU-DESSUS DE L'ENFER!\n"\
"VOUS SAVEZ QUE PERSONNE NE S'EN\n"\
"EST JAMAIS ECHAPPE, MAIS CES FUMIERS\n"\
"VONT REGRETTER DE VOUS AVOIR CONNU!\n"\
"VOUS REDESCENDEZ RAPIDEMENT VERS\n"\
"LA SURFACE DE L'ENFER.\n"\
"\n" \
"VOICI MAINTENANT LE CHAPITRE FINAL DE\n"\
"DOOM! -- L'ENFER."
#define E3TEXT "LE DEMON ARACHNEEN ET REPUGNANT\n"\
"QUI A DIRIGE L'INVASION DES BASES\n"\
"LUNAIRES ET SEME LA MORT VIENT DE SE\n"\
"FAIRE PULVERISER UNE FOIS POUR TOUTES.\n"\
"\n"\
"UNE PORTE SECRETE S'OUVRE. VOUS ENTREZ.\n"\
"VOUS AVEZ PROUVE QUE VOUS POUVIEZ\n"\
"RESISTER AUX HORREURS DE L'ENFER.\n"\
"IL SAIT ETRE BEAU JOUEUR, ET LORSQUE\n"\
"VOUS SORTEZ, VOUS REVOYEZ LES VERTES\n"\
"PRAIRIES DE LA TERRE, VOTRE PLANETE.\n"\
"\n"\
"VOUS VOUS DEMANDEZ CE QUI S'EST PASSE\n"\
"SUR TERRE PENDANT QUE VOUS AVEZ\n"\
"COMBATTU LE DEMON. HEUREUSEMENT,\n"\
"AUCUN GERME DU MAL N'A FRANCHI\n"\
"CETTE PORTE AVEC VOUS..."
// after level 6, put this:
#define C1TEXT "VOUS ETES AU PLUS PROFOND DE L'ASTROPORT\n" \
"INFESTE DE MONSTRES, MAIS QUELQUE CHOSE\n" \
"NE VA PAS. ILS ONT APPORTE LEUR PROPRE\n" \
"REALITE, ET LA TECHNOLOGIE DE L'ASTROPORT\n" \
"EST AFFECTEE PAR LEUR PRESENCE.\n" \
"\n"\
"DEVANT VOUS, VOUS VOYEZ UN POSTE AVANCE\n" \
"DE L'ENFER, UNE ZONE FORTIFIEE. SI VOUS\n" \
"POUVEZ PASSER, VOUS POURREZ PENETRER AU\n" \
"COEUR DE LA BASE HANTEE ET TROUVER \n" \
"L'INTERRUPTEUR DE CONTROLE QUI GARDE LA \n" \
"POPULATION DE LA TERRE EN OTAGE."
// After level 11, put this:
#define C2TEXT "VOUS AVEZ GAGNE! VOTRE VICTOIRE A PERMIS\n" \
"A L'HUMANITE D'EVACUER LA TERRE ET \n"\
"D'ECHAPPER AU CAUCHEMAR. VOUS ETES \n"\
"MAINTENANT LE DERNIER HUMAIN A LA SURFACE \n"\
"DE LA PLANETE. VOUS ETES ENTOURE DE \n"\
"MUTANTS CANNIBALES, D'EXTRATERRESTRES \n"\
"CARNIVORES ET D'ESPRITS DU MAL. VOUS \n"\
"ATTENDEZ CALMEMENT LA MORT, HEUREUX \n"\
"D'AVOIR PU SAUVER VOTRE RACE.\n"\
"MAIS UN MESSAGE VOUS PARVIENT SOUDAIN\n"\
"DE L'ESPACE: \"NOS CAPTEURS ONT LOCALISE\n"\
"LA SOURCE DE L'INVASION EXTRATERRESTRE.\n"\
"SI VOUS Y ALLEZ, VOUS POURREZ PEUT-ETRE\n"\
"LES ARRETER. LEUR BASE EST SITUEE AU COEUR\n"\
"DE VOTRE VILLE NATALE, PRES DE L'ASTROPORT.\n"\
"VOUS VOUS RELEVEZ LENTEMENT ET PENIBLEMENT\n"\
"ET VOUS REPARTEZ POUR LE FRONT."
// After level 20, put this:
#define C3TEXT "VOUS ETES AU COEUR DE LA CITE CORROMPUE,\n"\
"ENTOURE PAR LES CADAVRES DE VOS ENNEMIS.\n"\
"VOUS NE VOYEZ PAS COMMENT DETRUIRE LA PORTE\n"\
"DES CREATURES DE CE COTE. VOUS SERREZ\n"\
"LES DENTS ET PLONGEZ DANS L'OUVERTURE.\n"\
"\n"\
"IL DOIT Y AVOIR UN MOYEN DE LA FERMER\n"\
"DE L'AUTRE COTE. VOUS ACCEPTEZ DE\n"\
"TRAVERSER L'ENFER POUR LE FAIRE?"
// After level 29, put this:
#define C4TEXT "LE VISAGE HORRIBLE D'UN DEMON D'UNE\n"\
"TAILLE INCROYABLE S'EFFONDRE DEVANT\n"\
"VOUS LORSQUE VOUS TIREZ UNE SALVE DE\n"\
"ROQUETTES DANS SON CERVEAU. LE MONSTRE\n"\
"SE RATATINE, SES MEMBRES DECHIQUETES\n"\
"SE REPANDANT SUR DES CENTAINES DE\n"\
"KILOMETRES A LA SURFACE DE L'ENFER.\n"\
"\n"\
"VOUS AVEZ REUSSI. L'INVASION N'AURA.\n"\
"PAS LIEU. LA TERRE EST SAUVEE. L'ENFER\n"\
"EST ANEANTI. EN VOUS DEMANDANT OU IRONT\n"\
"MAINTENANT LES DAMNES, VOUS ESSUYEZ\n"\
"VOTRE FRONT COUVERT DE SUEUR ET REPARTEZ\n"\
"VERS LA TERRE. SA RECONSTRUCTION SERA\n"\
"BEAUCOUP PLUS DROLE QUE SA DESTRUCTION.\n"
// Before level 31, put this:
#define C5TEXT "FELICITATIONS! VOUS AVEZ TROUVE LE\n"\
"NIVEAU SECRET! IL SEMBLE AVOIR ETE\n"\
"CONSTRUIT PAR LES HUMAINS. VOUS VOUS\n"\
"DEMANDEZ QUELS PEUVENT ETRE LES\n"\
"HABITANTS DE CE COIN PERDU DE L'ENFER."
// Before level 32, put this:
#define C6TEXT "FELICITATIONS! VOUS AVEZ DECOUVERT\n"\
"LE NIVEAU SUPER SECRET! VOUS FERIEZ\n"\
"MIEUX DE FONCER DANS CELUI-LA!\n"
//
// Character cast strings F_FINALE.C
//
#define CC_ZOMBIE "ZOMBIE"
#define CC_SHOTGUN "TYPE AU FUSIL"
#define CC_HEAVY "MEC SUPER-ARME"
#define CC_IMP "DIABLOTIN"
#define CC_DEMON "DEMON"
#define CC_LOST "AME PERDUE"
#define CC_CACO "CACODEMON"
#define CC_HELL "CHEVALIER DE L'ENFER"
#define CC_BARON "BARON DE L'ENFER"
#define CC_ARACH "ARACHNOTRON"
#define CC_PAIN "ELEMENTAIRE DE LA DOULEUR"
#define CC_REVEN "REVENANT"
#define CC_MANCU "MANCUBUS"
#define CC_ARCH "ARCHI-INFAME"
#define CC_SPIDER "L'ARAIGNEE CERVEAU"
#define CC_CYBER "LE CYBERDEMON"
#define CC_HERO "NOTRE HEROS"
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

125
src/DOOM/d_items.c Normal file
View File

@ -0,0 +1,125 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "info.h" // We are referring to sprite numbers.
#include "d_items.h"
//
// PSPRITE ACTIONS for waepons.
// This struct controls the weapon animations.
//
// Each entry is:
// ammo/amunition type
// upstate
// downstate
// readystate
// atkstate, i.e. attack/fire/hit frame
// flashstate, muzzle flash
//
weaponinfo_t weaponinfo[NUMWEAPONS] =
{
{
// fist
am_noammo,
S_PUNCHUP,
S_PUNCHDOWN,
S_PUNCH,
S_PUNCH1,
S_NULL
},
{
// pistol
am_clip,
S_PISTOLUP,
S_PISTOLDOWN,
S_PISTOL,
S_PISTOL1,
S_PISTOLFLASH
},
{
// shotgun
am_shell,
S_SGUNUP,
S_SGUNDOWN,
S_SGUN,
S_SGUN1,
S_SGUNFLASH1
},
{
// chaingun
am_clip,
S_CHAINUP,
S_CHAINDOWN,
S_CHAIN,
S_CHAIN1,
S_CHAINFLASH1
},
{
// missile launcher
am_misl,
S_MISSILEUP,
S_MISSILEDOWN,
S_MISSILE,
S_MISSILE1,
S_MISSILEFLASH1
},
{
// plasma rifle
am_cell,
S_PLASMAUP,
S_PLASMADOWN,
S_PLASMA,
S_PLASMA1,
S_PLASMAFLASH1
},
{
// bfg 9000
am_cell,
S_BFGUP,
S_BFGDOWN,
S_BFG,
S_BFG1,
S_BFGFLASH1
},
{
// chainsaw
am_noammo,
S_SAWUP,
S_SAWDOWN,
S_SAW,
S_SAW1,
S_NULL
},
{
// super shotgun
am_shell,
S_DSGUNUP,
S_DSGUNDOWN,
S_DSGUN,
S_DSGUN1,
S_DSGUNFLASH1
},
};

50
src/DOOM/d_items.h Normal file
View File

@ -0,0 +1,50 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Items: key cards, artifacts, weapon, ammunition.
//
//-----------------------------------------------------------------------------
#ifndef __D_ITEMS__
#define __D_ITEMS__
#include "doomdef.h"
// Weapon info: sprite frames, ammunition use.
typedef struct
{
ammotype_t ammo;
int upstate;
int downstate;
int readystate;
int atkstate;
int flashstate;
} weaponinfo_t;
extern weaponinfo_t weaponinfo[NUMWEAPONS];
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

1258
src/DOOM/d_main.c Normal file

File diff suppressed because it is too large Load Diff

59
src/DOOM/d_main.h Normal file
View File

@ -0,0 +1,59 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// System specific interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __D_MAIN__
#define __D_MAIN__
#include "d_event.h"
#define MAXWADFILES 20
extern char* wadfiles[MAXWADFILES];
void D_AddFile(char* file);
//
// D_DoomMain()
// Not a globally visible function, just included for source reference,
// calls all startup code, parses command line options.
// If not overrided by user input, calls N_AdvanceDemo.
//
void D_DoomMain(void);
// Called by IO functions when input is detected.
void D_PostEvent(event_t* ev);
//
// BASE LEVEL
//
void D_PageTicker(void);
void D_PageDrawer(void);
void D_AdvanceDemo(void);
void D_StartTitle(void);
#endif

856
src/DOOM/d_net.c Normal file
View File

@ -0,0 +1,856 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// DOOM Network game communication and protocol,
// all OS independend parts.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "m_menu.h"
#include "i_system.h"
#include "i_video.h"
#include "i_net.h"
#include "g_game.h"
#include "doomdef.h"
#include "doomstat.h"
//
// NETWORKING
//
// gametic is the tic about to (or currently being) run
// maketic is the tick that hasn't had control made for it yet
// nettics[] has the maketics for all players
//
// a gametic cannot be run until nettics[] > gametic for all players
//
#define NCMD_EXIT 0x80000000
#define NCMD_RETRANSMIT 0x40000000
#define NCMD_SETUP 0x20000000
#define NCMD_KILL 0x10000000 // kill game
#define NCMD_CHECKSUM 0x0fffffff
#define RESENDCOUNT 10
#define PL_DRONE 0x80 // bit flag in doomdata->player
doomcom_t* doomcom;
doomdata_t* netbuffer; // points inside doomcom
ticcmd_t localcmds[BACKUPTICS];
ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
int nettics[MAXNETNODES];
doom_boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
doom_boolean remoteresend[MAXNETNODES]; // set when local needs tics
int resendto[MAXNETNODES]; // set when remote needs tics
int resendcount[MAXNETNODES];
int nodeforplayer[MAXPLAYERS];
int maketic;
int lastnettic;
int skiptics;
int ticdup;
int maxsend; // BACKUPTICS/(2*ticdup)-1
doom_boolean reboundpacket;
doomdata_t reboundstore;
char exitmsg[80];
int gametime;
int frametics[4];
int frameon;
int frameskip[4];
int oldnettics;
extern int viewangleoffset;
extern doom_boolean advancedemo;
void D_ProcessEvents(void);
void G_BuildTiccmd(ticcmd_t* cmd);
void D_DoAdvanceDemo(void);
//
//
//
int NetbufferSize(void)
{
return (int)(long long)&(((doomdata_t*)0)->cmds[netbuffer->numtics]);
}
//
// Checksum
//
unsigned NetbufferChecksum(void)
{
unsigned c;
int i, l;
c = 0x1234567;
// FIXME -endianess?
// #ifdef NORMALUNIX
return 0; // byte order problems
// #endif
l = (NetbufferSize() - (int)(long long)&(((doomdata_t*)0)->retransmitfrom)) / 4;
for (i = 0; i < l; i++)
c += ((unsigned*)&netbuffer->retransmitfrom)[i] * (i + 1);
return c & NCMD_CHECKSUM;
}
//
//
//
int ExpandTics(int low)
{
int delta;
delta = low - (maketic & 0xff);
if (delta >= -64 && delta <= 64)
return (maketic & ~0xff) + low;
if (delta > 64)
return (maketic & ~0xff) - 256 + low;
if (delta < -64)
return (maketic & ~0xff) + 256 + low;
//I_Error("Error: ExpandTics: strange value %i at maketic %i", low, maketic);
doom_strcpy(error_buf, "Error: ExpandTics: strange value ");
doom_concat(error_buf, doom_itoa(low, 10));
doom_concat(error_buf, " at maketic ");
doom_concat(error_buf, doom_itoa(maketic, 10));
I_Error(error_buf);
return 0;
}
//
// HSendPacket
//
void HSendPacket(int node, int flags)
{
netbuffer->checksum = NetbufferChecksum() | flags;
if (!node)
{
reboundstore = *netbuffer;
reboundpacket = true;
return;
}
if (demoplayback)
return;
if (!netgame)
I_Error("Error: Tried to transmit to another node");
doomcom->command = CMD_SEND;
doomcom->remotenode = node;
doomcom->datalength = NetbufferSize();
if (debugfile)
{
int i;
int realretrans;
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics(netbuffer->retransmitfrom);
else
realretrans = -1;
{
//fprintf(debugfile, "send (%i + %i, R %i) [%i] ",
// ExpandTics(netbuffer->starttic),
// netbuffer->numtics, realretrans, doomcom->datalength);
doom_fprint(debugfile, "send (");
doom_fprint(debugfile, doom_itoa(ExpandTics(netbuffer->starttic), 10));
doom_fprint(debugfile, " + ");
doom_fprint(debugfile, doom_itoa(netbuffer->numtics, 10));
doom_fprint(debugfile, ", R ");
doom_fprint(debugfile, doom_itoa(realretrans, 10));
doom_fprint(debugfile, ") [");
doom_fprint(debugfile, doom_itoa(doomcom->datalength, 10));
doom_fprint(debugfile, "] ");
}
for (i = 0; i < doomcom->datalength; i++)
{
//fprintf(debugfile, "%i ", ((byte*)netbuffer)[i]);
doom_fprint(debugfile, doom_itoa(((byte*)netbuffer)[i], 10));
doom_fprint(debugfile, " ");
}
doom_fprint(debugfile, "\n");
}
I_NetCmd();
}
//
// HGetPacket
// Returns false if no packet is waiting
//
doom_boolean HGetPacket(void)
{
if (reboundpacket)
{
*netbuffer = reboundstore;
doomcom->remotenode = 0;
reboundpacket = false;
return true;
}
if (!netgame)
return false;
if (demoplayback)
return false;
doomcom->command = CMD_GET;
I_NetCmd();
if (doomcom->remotenode == -1)
return false;
if (doomcom->datalength != NetbufferSize())
{
if (debugfile)
{
//fprintf(debugfile, "bad packet length %i\n", doomcom->datalength);
doom_fprint(debugfile, "bad packet length ");
doom_fprint(debugfile, doom_itoa(doomcom->datalength, 10));
doom_fprint(debugfile, "\n");
}
return false;
}
if (NetbufferChecksum() != (netbuffer->checksum & NCMD_CHECKSUM))
{
if (debugfile)
{
doom_fprint(debugfile, "bad packet checksum\n");
}
return false;
}
if (debugfile)
{
int realretrans;
int i;
if (netbuffer->checksum & NCMD_SETUP)
{
doom_fprint(debugfile, "setup packet\n");
}
else
{
if (netbuffer->checksum & NCMD_RETRANSMIT)
realretrans = ExpandTics(netbuffer->retransmitfrom);
else
realretrans = -1;
{
//fprintf(debugfile, "get %i = (%i + %i, R %i)[%i] ",
// doomcom->remotenode,
// ExpandTics(netbuffer->starttic),
// netbuffer->numtics, realretrans, doomcom->datalength);
doom_fprint(debugfile, "get ");
doom_fprint(debugfile, doom_itoa(doomcom->remotenode, 10));
doom_fprint(debugfile, " = (");
doom_fprint(debugfile, doom_itoa(ExpandTics(netbuffer->starttic), 10));
doom_fprint(debugfile, " + ");
doom_fprint(debugfile, doom_itoa(netbuffer->numtics, 10));
doom_fprint(debugfile, ", R ");
doom_fprint(debugfile, doom_itoa(realretrans, 10));
doom_fprint(debugfile, ")[");
doom_fprint(debugfile, doom_itoa(doomcom->datalength, 10));
doom_fprint(debugfile, "] ");
}
for (i = 0; i < doomcom->datalength; i++)
{
//fprintf(debugfile, "%i ", ((byte*)netbuffer)[i]);
doom_fprint(debugfile, doom_itoa(((byte*)netbuffer)[i], 10));
doom_fprint(debugfile, " ");
}
doom_fprint(debugfile, "\n");
}
}
return true;
}
//
// GetPackets
//
void GetPackets(void)
{
int netconsole;
int netnode;
ticcmd_t* src, *dest;
int realend;
int realstart;
while (HGetPacket())
{
if (netbuffer->checksum & NCMD_SETUP)
continue; // extra setup packet
netconsole = netbuffer->player & ~PL_DRONE;
netnode = doomcom->remotenode;
// to save bytes, only the low byte of tic numbers are sent
// Figure out what the rest of the bytes are
realstart = ExpandTics(netbuffer->starttic);
realend = (realstart + netbuffer->numtics);
// check for exiting the game
if (netbuffer->checksum & NCMD_EXIT)
{
if (!nodeingame[netnode])
continue;
nodeingame[netnode] = false;
playeringame[netconsole] = false;
doom_strcpy(exitmsg, "Player 1 left the game");
exitmsg[7] += netconsole;
players[consoleplayer].message = exitmsg;
if (demorecording)
G_CheckDemoStatus();
continue;
}
// check for a remote game kill
if (netbuffer->checksum & NCMD_KILL)
I_Error("Error: Killed by network driver");
nodeforplayer[netconsole] = netnode;
// check for retransmit request
if (resendcount[netnode] <= 0
&& (netbuffer->checksum & NCMD_RETRANSMIT))
{
resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
if (debugfile)
{
//fprintf(debugfile, "retransmit from %i\n", resendto[netnode]);
doom_fprint(debugfile, "retransmit from ");
doom_fprint(debugfile, doom_itoa(resendto[netnode], 10));
doom_fprint(debugfile, "\n");
}
resendcount[netnode] = RESENDCOUNT;
}
else
resendcount[netnode]--;
// check for out of order / duplicated packet
if (realend == nettics[netnode])
continue;
if (realend < nettics[netnode])
{
if (debugfile)
{
//fprintf(debugfile,
// "out of order packet (%i + %i)\n",
// realstart, netbuffer->numtics);
doom_fprint(debugfile, "out of order packet (");
doom_fprint(debugfile, doom_itoa(realstart, 10));
doom_fprint(debugfile, " + ");
doom_fprint(debugfile, doom_itoa(netbuffer->numtics, 10));
doom_fprint(debugfile, ")\n");
}
continue;
}
// check for a missed packet
if (realstart > nettics[netnode])
{
// stop processing until the other system resends the missed tics
if (debugfile)
{
//fprintf(debugfile,
// "missed tics from %i (%i - %i)\n",
// netnode, realstart, nettics[netnode]);
doom_fprint(debugfile, "missed tics from ");
doom_fprint(debugfile, doom_itoa(netnode, 10));
doom_fprint(debugfile, " (");
doom_fprint(debugfile, doom_itoa(realstart, 10));
doom_fprint(debugfile, " - ");
doom_fprint(debugfile, doom_itoa(nettics[netnode], 10));
doom_fprint(debugfile, ")\n");
}
remoteresend[netnode] = true;
continue;
}
// update command store from the packet
{
int start;
remoteresend[netnode] = false;
start = nettics[netnode] - realstart;
src = &netbuffer->cmds[start];
while (nettics[netnode] < realend)
{
dest = &netcmds[netconsole][nettics[netnode] % BACKUPTICS];
nettics[netnode]++;
*dest = *src;
src++;
}
}
}
}
//
// NetUpdate
// Builds ticcmds for console player,
// sends out a packet
//
void NetUpdate(void)
{
int nowtime;
int newtics;
int i, j;
int realstart;
int gameticdiv;
// check time
nowtime = I_GetTime() / ticdup;
newtics = nowtime - gametime;
gametime = nowtime;
if (newtics <= 0) // nothing new to update
goto listen;
if (skiptics <= newtics)
{
newtics -= skiptics;
skiptics = 0;
}
else
{
skiptics -= newtics;
newtics = 0;
}
netbuffer->player = consoleplayer;
// build new ticcmds for console player
gameticdiv = gametic / ticdup;
for (i = 0; i < newtics; i++)
{
I_StartTic();
D_ProcessEvents();
if (maketic - gameticdiv >= BACKUPTICS / 2 - 1)
break; // can't hold any more
//doom_print ("mk:%i ",maketic);
G_BuildTiccmd(&localcmds[maketic % BACKUPTICS]);
maketic++;
}
if (singletics)
return; // singletic update is syncronous
// send the packet to the other nodes
for (i = 0; i < doomcom->numnodes; i++)
if (nodeingame[i])
{
netbuffer->starttic = realstart = resendto[i];
netbuffer->numtics = maketic - realstart;
if (netbuffer->numtics > BACKUPTICS)
I_Error("Error: NetUpdate: netbuffer->numtics > BACKUPTICS");
resendto[i] = maketic - doomcom->extratics;
for (j = 0; j < netbuffer->numtics; j++)
netbuffer->cmds[j] =
localcmds[(realstart + j) % BACKUPTICS];
if (remoteresend[i])
{
netbuffer->retransmitfrom = nettics[i];
HSendPacket(i, NCMD_RETRANSMIT);
}
else
{
netbuffer->retransmitfrom = 0;
HSendPacket(i, 0);
}
}
// listen for other packets
listen:
GetPackets();
}
//
// CheckAbort
//
void CheckAbort(void)
{
event_t* ev;
int stoptic;
stoptic = I_GetTime() + 2;
while (I_GetTime() < stoptic)
I_StartTic();
I_StartTic();
for (; eventtail != eventhead
; )
{
ev = &events[eventtail];
if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
I_Error("Error: Network game synchronization aborted.");
}
eventtail++;
eventtail = (eventtail) & (MAXEVENTS - 1);
}
//
// D_ArbitrateNetStart
//
void D_ArbitrateNetStart(void)
{
int i;
doom_boolean gotinfo[MAXNETNODES];
autostart = true;
doom_memset(gotinfo, 0, sizeof(gotinfo));
if (doomcom->consoleplayer)
{
// listen for setup info from key player
doom_print("listening for network start info...\n");
while (1)
{
CheckAbort();
if (!HGetPacket())
continue;
if (netbuffer->checksum & NCMD_SETUP)
{
if (netbuffer->player != VERSION)
I_Error("Error: Different DOOM versions cannot play a net game!");
startskill = netbuffer->retransmitfrom & 15;
deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
startmap = netbuffer->starttic & 0x3f;
startepisode = netbuffer->starttic >> 6;
return;
}
}
}
else
{
// key player, send the setup info
doom_print("sending network start info...\n");
do
{
CheckAbort();
for (i = 0; i < doomcom->numnodes; i++)
{
netbuffer->retransmitfrom = startskill;
if (deathmatch)
netbuffer->retransmitfrom |= (deathmatch << 6);
if (nomonsters)
netbuffer->retransmitfrom |= 0x20;
if (respawnparm)
netbuffer->retransmitfrom |= 0x10;
netbuffer->starttic = startepisode * 64 + startmap;
netbuffer->player = VERSION;
netbuffer->numtics = 0;
HSendPacket(i, NCMD_SETUP);
}
#if 1
for (i = 10; i && HGetPacket(); --i)
{
if ((netbuffer->player & 0x7f) < MAXNETNODES)
gotinfo[netbuffer->player & 0x7f] = true;
}
#else
while (HGetPacket())
{
gotinfo[netbuffer->player & 0x7f] = true;
}
#endif
for (i = 1; i < doomcom->numnodes; i++)
if (!gotinfo[i])
break;
} while (i < doomcom->numnodes);
}
}
//
// D_CheckNetGame
// Works out player numbers among the net participants
//
void D_CheckNetGame(void)
{
int i;
for (i = 0; i < MAXNETNODES; i++)
{
nodeingame[i] = false;
nettics[i] = 0;
remoteresend[i] = false; // set when local needs tics
resendto[i] = 0; // which tic to start sending
}
// I_InitNetwork sets doomcom and netgame
I_InitNetwork();
if (doomcom->id != DOOMCOM_ID)
I_Error("Error: Doomcom buffer invalid!");
netbuffer = &doomcom->data;
consoleplayer = displayplayer = doomcom->consoleplayer;
if (netgame)
D_ArbitrateNetStart();
//doom_print("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
// startskill, deathmatch, startmap, startepisode);
doom_print("startskill ");
doom_print(doom_itoa(startskill, 10));
doom_print(" deathmatch: ");
doom_print(doom_itoa(deathmatch, 10));
doom_print(" startmap: ");
doom_print(doom_itoa(startmap, 10));
doom_print(" startepisode: ");
doom_print(doom_itoa(startepisode, 10));
doom_print("\n");
// read values out of doomcom
ticdup = doomcom->ticdup;
maxsend = BACKUPTICS / (2 * ticdup) - 1;
if (maxsend < 1)
maxsend = 1;
for (i = 0; i < doomcom->numplayers; i++)
playeringame[i] = true;
for (i = 0; i < doomcom->numnodes; i++)
nodeingame[i] = true;
//doom_print("player %i of %i (%i nodes)\n",
// consoleplayer + 1, doomcom->numplayers, doomcom->numnodes);
doom_print("player ");
doom_print(doom_itoa(consoleplayer + 1, 10));
doom_print(" of ");
doom_print(doom_itoa(doomcom->numplayers, 10));
doom_print(" (");
doom_print(doom_itoa(doomcom->numnodes, 10));
doom_print(" nodes)\n");
}
//
// D_QuitNetGame
// Called before quitting to leave a net game
// without hanging the other players
//
void D_QuitNetGame(void)
{
int i, j;
if (debugfile)
doom_close(debugfile);
if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
return;
// send a bunch of packets for security
netbuffer->player = consoleplayer;
netbuffer->numtics = 0;
for (i = 0; i < 4; i++)
{
for (j = 1; j < doomcom->numnodes; j++)
if (nodeingame[j])
HSendPacket(j, NCMD_EXIT);
I_WaitVBL(1);
}
}
//
// TryRunTics
//
void TryRunTics(void)
{
int i;
int lowtic;
int entertic;
static int oldentertics;
int realtics;
int availabletics;
int counts;
int numplaying;
// get real tics
entertic = I_GetTime() / ticdup;
realtics = entertic - oldentertics;
oldentertics = entertic;
// get available tics
NetUpdate();
lowtic = DOOM_MAXINT;
numplaying = 0;
for (i = 0; i < doomcom->numnodes; i++)
{
if (nodeingame[i])
{
numplaying++;
if (nettics[i] < lowtic)
lowtic = nettics[i];
}
}
availabletics = lowtic - gametic / ticdup;
// decide how many tics to run
if (realtics < availabletics - 1)
counts = realtics + 1;
else if (realtics < availabletics)
counts = realtics;
else
counts = availabletics;
if (counts < 1)
counts = 1;
frameon++;
if (debugfile)
{
//fprintf(debugfile,
// "=======real: %i avail: %i game: %i\n",
// realtics, availabletics, counts);
doom_fprint(debugfile, "=======real: ");
doom_fprint(debugfile, doom_itoa(realtics, 10));
doom_fprint(debugfile, " avail: ");
doom_fprint(debugfile, doom_itoa(availabletics, 10));
doom_fprint(debugfile, " game: ");
doom_fprint(debugfile, doom_itoa(counts, 10));
doom_fprint(debugfile, "\n");
}
if (!demoplayback)
{
// ideally nettics[0] should be 1 - 3 tics above lowtic
// if we are consistantly slower, speed up time
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
break;
if (consoleplayer == i)
{
// the key player does not adapt
}
else
{
if (nettics[0] <= nettics[nodeforplayer[i]])
{
gametime--;
// doom_print ("-");
}
frameskip[frameon & 3] = (oldnettics > nettics[nodeforplayer[i]]);
oldnettics = nettics[0];
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
{
skiptics = 1;
// doom_print ("+");
}
}
}// demoplayback
// wait for new tics if needed
while (lowtic < gametic / ticdup + counts)
{
NetUpdate();
lowtic = DOOM_MAXINT;
for (i = 0; i < doomcom->numnodes; i++)
if (nodeingame[i] && nettics[i] < lowtic)
lowtic = nettics[i];
if (lowtic < gametic / ticdup)
I_Error("Error: TryRunTics: lowtic < gametic");
// don't stay in here forever -- give the menu a chance to work
if (I_GetTime() / ticdup - entertic >= 20)
{
M_Ticker();
return;
}
}
// run the count * ticdup dics
while (counts--)
{
for (i = 0; i < ticdup; i++)
{
if (gametic / ticdup > lowtic)
I_Error("Error: gametic>lowtic");
if (advancedemo)
D_DoAdvanceDemo();
M_Ticker();
G_Ticker();
gametic++;
// modify command for duplicated tics
if (i != ticdup - 1)
{
ticcmd_t* cmd;
int buf;
int j;
buf = (gametic / ticdup) % BACKUPTICS;
for (j = 0; j < MAXPLAYERS; j++)
{
cmd = &netcmds[j][buf];
cmd->chatchar = 0;
if (cmd->buttons & BT_SPECIAL)
cmd->buttons = 0;
}
}
}
NetUpdate(); // check for new console commands
}
}

137
src/DOOM/d_net.h Normal file
View File

@ -0,0 +1,137 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Networking stuff.
//
//-----------------------------------------------------------------------------
#ifndef __D_NET__
#define __D_NET__
#include "d_player.h"
//
// Network play related stuff.
// There is a data struct that stores network
// communication related stuff, and another
// one that defines the actual packets to
// be transmitted.
//
#define DOOMCOM_ID 0x12345678l
// Max computers/players in a game.
#define MAXNETNODES 8
// Networking and tick handling related.
#define BACKUPTICS 12
typedef enum
{
CMD_SEND = 1,
CMD_GET = 2
} command_t;
//
// Network packet data.
//
typedef struct
{
// High bit is retransmit request.
unsigned checksum;
// Only valid if NCMD_RETRANSMIT.
byte retransmitfrom;
byte starttic;
byte player;
byte numtics;
ticcmd_t cmds[BACKUPTICS];
} doomdata_t;
typedef struct
{
// Supposed to be DOOMCOM_ID?
long id;
// DOOM executes an int to execute commands.
short intnum;
// Communication between DOOM and the driver.
// Is CMD_SEND or CMD_GET.
short command;
// Is dest for send, set by get (-1 = no packet).
short remotenode;
// Number of bytes in doomdata to be sent
short datalength;
// Info common to all nodes.
// Console is allways node 0.
short numnodes;
// Flag: 1 = no duplication, 2-5 = dup for slow nets.
short ticdup;
// Flag: 1 = send a backup tic in every packet.
short extratics;
// Flag: 1 = deathmatch.
short deathmatch;
// Flag: -1 = new game, 0-5 = load savegame
short savegame;
short episode; // 1-3
short map; // 1-9
short skill; // 1-5
// Info specific to this node.
short consoleplayer;
short numplayers;
// These are related to the 3-display mode,
// in which two drones looking left and right
// were used to render two additional views
// on two additional computers.
// Probably not operational anymore.
// 1 = left, 0 = center, -1 = right
short angleoffset;
// 1 = drone
short drone;
// The packet data to be sent.
doomdata_t data;
} doomcom_t;
// Create any new ticcmds and broadcast to other players.
void NetUpdate(void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame(void);
//? how many ticks to run?
void TryRunTics(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

209
src/DOOM/d_player.h Normal file
View File

@ -0,0 +1,209 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __D_PLAYER__
#define __D_PLAYER__
// The player data structure depends on a number
// of other structs: items (internal inventory),
// animation states (closely tied to the sprites
// used to represent them, unfortunately).
#include "d_items.h"
#include "p_pspr.h"
// In addition, the player is just a special
// case of the generic moving object/actor.
#include "p_mobj.h"
// Finally, for odd reasons, the player input
// is buffered within the player data struct,
// as commands per game tick.
#include "d_ticcmd.h"
//
// Player states.
//
typedef enum
{
// Playing or camping.
PST_LIVE,
// Dead on the ground, view follows killer.
PST_DEAD,
// Ready to restart/respawn???
PST_REBORN
} playerstate_t;
//
// Player internal flags, for cheats and debug.
//
typedef enum
{
// No clipping, walk through barriers.
CF_NOCLIP = 1,
// No damage, no health loss.
CF_GODMODE = 2,
// Not really a cheat, just a debug aid.
CF_NOMOMENTUM = 4
} cheat_t;
//
// Extended player object info: player_t
//
typedef struct player_s
{
mobj_t* mo;
playerstate_t playerstate;
ticcmd_t cmd;
// Determine POV,
// including viewpoint bobbing during movement.
// Focal origin above r.z
fixed_t viewz;
// Base height above floor for viewz.
fixed_t viewheight;
// Bob/squat speed.
fixed_t deltaviewheight;
// bounded/scaled total momentum.
fixed_t bob;
// This is only used between levels,
// mo->health is used during levels.
int health;
int armorpoints;
// Armor type is 0-2.
int armortype;
// Power ups. invinc and invis are tic counters.
int powers[NUMPOWERS];
doom_boolean cards[NUMCARDS];
doom_boolean backpack;
// Frags, kills of other players.
int frags[MAXPLAYERS];
weapontype_t readyweapon;
// Is wp_nochange if not changing.
weapontype_t pendingweapon;
doom_boolean weaponowned[NUMWEAPONS];
int ammo[NUMAMMO];
int maxammo[NUMAMMO];
// True if button down last tic.
int attackdown;
int usedown;
// Bit flags, for cheats and debug.
// See cheat_t, above.
int cheats;
// Refired shots are less accurate.
int refire;
// For intermission stats.
int killcount;
int itemcount;
int secretcount;
// Hint messages.
char* message;
// For screen flashing (red or bright).
int damagecount;
int bonuscount;
// Who did damage (0 for floors/ceilings).
mobj_t* attacker;
// So gun flashes light up areas.
int extralight;
// Current PLAYPAL, ???
// can be set to REDCOLORMAP for pain, etc.
int fixedcolormap;
// Player skin colorshift,
// 0-3 for which color to draw player.
int colormap;
// Overlay view sprites (gun, etc).
pspdef_t psprites[NUMPSPRITES];
// True if secret level has been done.
doom_boolean didsecret;
} player_t;
//
// INTERMISSION
// Structure passed e.g. to WI_Start(wb)
//
typedef struct
{
doom_boolean in; // whether the player is in game
// Player stats, kills, collected items etc.
int skills;
int sitems;
int ssecret;
int stime;
int frags[4];
int score; // current score on entry, modified on return
} wbplayerstruct_t;
typedef struct
{
int epsd; // episode # (0-2)
// if true, splash the secret level
doom_boolean didsecret;
// previous and next levels, origin 0
int last;
int next;
int maxkills;
int maxitems;
int maxsecret;
int maxfrags;
// the par time
int partime;
// index of this player in game
int pnum;
wbplayerstruct_t plyr[MAXPLAYERS];
} wbstartstruct_t;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

48
src/DOOM/d_textur.h Normal file
View File

@ -0,0 +1,48 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Typedefs related to to textures etc.,
// isolated here to make it easier separating modules.
//
//-----------------------------------------------------------------------------
#ifndef __D_TEXTUR__
#define __D_TEXTUR__
#include "doomtype.h"
//
// Flats?
//
// a pic is an unmasked block of pixels
typedef struct
{
byte width;
byte height;
byte data;
} pic_t;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

67
src/DOOM/d_think.h Normal file
View File

@ -0,0 +1,67 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// MapObj data. Map Objects or mobjs are actors, entities,
// thinker, take-your-pick... anything that moves, acts, or
// suffers state changes of more or less violent nature.
//
//-----------------------------------------------------------------------------
#ifndef __D_THINK__
#define __D_THINK__
//
// Experimental stuff.
// To compile this as "ANSI C with classes"
// we will need to handle the various
// action functions cleanly.
//
typedef void (*actionf_v)();
typedef void (*actionf_p1)(void*);
typedef void (*actionf_p2)(void*, void*);
typedef union
{
actionf_p1 acp1;
actionf_v acv;
actionf_p2 acp2;
} actionf_t;
// Historically, "think_t" is yet another
// function pointer to a routine to handle
// an actor.
typedef actionf_t think_t;
// Doubly linked list of actors.
typedef struct thinker_s
{
struct thinker_s* prev;
struct thinker_s* next;
think_t function;
} thinker_t;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

50
src/DOOM/d_ticcmd.h Normal file
View File

@ -0,0 +1,50 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __D_TICCMD__
#define __D_TICCMD__
#include "doomtype.h"
// The data sampled per tick (single player)
// and transmitted to other peers (multiplayer).
// Mainly movements/button commands per game tick,
// plus a checksum for internal state consistency.
typedef struct
{
char forwardmove; // *2048 for move
char sidemove; // *2048 for move
short angleturn; // <<16 for angle delta
short consistancy; // checks for net game
byte chatchar;
byte buttons;
} ticcmd_t;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

56
src/DOOM/doom_config.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef __DOOM_CONFIG_H__
#define __DOOM_CONFIG_H__
#if defined(WIN32)
#define DOOM_WIN32
#elif defined(__APPLE__)
#define DOOM_APPLE
#else
#define DOOM_LINUX
#endif
#include "DOOM.h"
#define doom_abs(x) ((x) < 0 ? -(x) : (x))
extern char error_buf[260];
extern int doom_flags;
extern doom_print_fn doom_print;
extern doom_malloc_fn doom_malloc;
extern doom_free_fn doom_free;
extern doom_open_fn doom_open;
extern doom_close_fn doom_close;
extern doom_read_fn doom_read;
extern doom_write_fn doom_write;
extern doom_seek_fn doom_seek;
extern doom_tell_fn doom_tell;
extern doom_eof_fn doom_eof;
extern doom_gettime_fn doom_gettime;
extern doom_exit_fn doom_exit;
extern doom_getenv_fn doom_getenv;
const char* doom_itoa(int i, int radix);
const char* doom_ctoa(char c);
const char* doom_ptoa(void* p);
void doom_memset(void* ptr, int value, int num);
void* doom_memcpy(void* destination, const void* source, int num);
int doom_fprint(void* handle, const char* str);
int doom_strlen(const char* str);
char* doom_concat(char* dst, const char* src);
char* doom_strcpy(char* destination, const char* source);
char* doom_strncpy(char* destination, const char* source, int num);
int doom_strcmp(const char* str1, const char* str2);
int doom_strncmp(const char* str1, const char* str2, int n);
int doom_strcasecmp(const char* str1, const char* str2);
int doom_strncasecmp(const char* str1, const char* str2, int n);
int doom_atoi(const char* str);
int doom_atox(const char* str);
int doom_toupper(int c);
#endif

215
src/DOOM/doomdata.h Normal file
View File

@ -0,0 +1,215 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// all external data is defined here
// most of the data is loaded into different structures at run time
// some internal structures shared by many modules are here
//
//-----------------------------------------------------------------------------
#ifndef __DOOMDATA__
#define __DOOMDATA__
// The most basic types we use, portability.
#include "doomtype.h"
// Some global defines, that configure the game.
#include "doomdef.h"
//
// Map level types.
// The following data structures define the persistent format
// used in the lumps of the WAD files.
//
// Lump order in a map WAD: each map needs a couple of lumps
// to provide a complete scene geometry description.
enum
{
ML_LABEL, // A separator, name, ExMx or MAPxx
ML_THINGS, // Monsters, items..
ML_LINEDEFS, // LineDefs, from editing
ML_SIDEDEFS, // SideDefs, from editing
ML_VERTEXES, // Vertices, edited and BSP splits generated
ML_SEGS, // LineSegs, from LineDefs split by BSP
ML_SSECTORS, // SubSectors, list of LineSegs
ML_NODES, // BSP nodes
ML_SECTORS, // Sectors, from editing
ML_REJECT, // LUT, sector-sector visibility
ML_BLOCKMAP // LUT, motion clipping, walls/grid element
};
// A single Vertex.
typedef struct
{
short x;
short y;
} mapvertex_t;
// A SideDef, defining the visual appearance of a wall,
// by setting textures and offsets.
typedef struct
{
short textureoffset;
short rowoffset;
char toptexture[8];
char bottomtexture[8];
char midtexture[8];
// Front sector, towards viewer.
short sector;
} mapsidedef_t;
// A LineDef, as used for editing, and as input
// to the BSP builder.
typedef struct
{
short v1;
short v2;
short flags;
short special;
short tag;
// sidenum[1] will be -1 if one sided
short sidenum[2];
} maplinedef_t;
//
// LineDef attributes.
//
// Solid, is an obstacle.
#define ML_BLOCKING 1
// Blocks monsters only.
#define ML_BLOCKMONSTERS 2
// Backside will not be present at all
// if not two sided.
#define ML_TWOSIDED 4
// If a texture is pegged, the texture will have
// the end exposed to air held constant at the
// top or bottom of the texture (stairs or pulled
// down things) and will move with a height change
// of one of the neighbor sectors.
// Unpegged textures allways have the first row of
// the texture at the top pixel of the line for both
// top and bottom textures (use next to windows).
// upper texture unpegged
#define ML_DONTPEGTOP 8
// lower texture unpegged
#define ML_DONTPEGBOTTOM 16
// In AutoMap: don't map as two sided: IT'S A SECRET!
#define ML_SECRET 32
// Sound rendering: don't let sound cross two of these.
#define ML_SOUNDBLOCK 64
// Don't draw on the automap at all.
#define ML_DONTDRAW 128
// Set if already seen, thus drawn in automap.
#define ML_MAPPED 256
// Sector definition, from editing.
typedef struct
{
short floorheight;
short ceilingheight;
char floorpic[8];
char ceilingpic[8];
short lightlevel;
short special;
short tag;
} mapsector_t;
// SubSector, as generated by BSP.
typedef struct
{
short numsegs;
// Index of first one, segs are stored sequentially.
short firstseg;
} mapsubsector_t;
// LineSeg, generated by splitting LineDefs
// using partition lines selected by BSP builder.
typedef struct
{
short v1;
short v2;
short angle;
short linedef;
short side;
short offset;
} mapseg_t;
//
// BSP node structure.
//
// Indicate a leaf.
#define NF_SUBSECTOR 0x8000
typedef struct
{
// Partition line from (x,y) to x+dx,y+dy)
short x;
short y;
short dx;
short dy;
// Bounding box for each child,
// clip against view frustum.
short bbox[2][4];
// If NF_SUBSECTOR its a subsector,
// else it's a node of another subtree.
unsigned short children[2];
} mapnode_t;
// Thing definition, position, orientation and type,
// plus skill/visibility flags and attributes.
typedef struct
{
short x;
short y;
short angle;
short type;
short options;
} mapthing_t;
#endif // __DOOMDATA__
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

27
src/DOOM/doomdef.c Normal file
View File

@ -0,0 +1,27 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// DoomDef - basic defines for DOOM, e.g. Version, game mode
// and skill level, and display parameters.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"

264
src/DOOM/doomdef.h Normal file
View File

@ -0,0 +1,264 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Internally used data structures for virtually everything,
// key definitions, lots of other stuff.
//
//-----------------------------------------------------------------------------
#ifndef __DOOMDEF__
#define __DOOMDEF__
//
// Global parameters/defines.
//
// DOOM version
enum
{
VERSION = 110
};
// Game mode handling - identify IWAD version
// to handle IWAD dependend animations etc.
typedef enum
{
shareware, // DOOM 1 shareware, E1, M9
registered, // DOOM 1 registered, E3, M27
commercial, // DOOM 2 retail, E1 M34
// DOOM 2 german edition not handled
retail, // DOOM 1 retail, E4, M36
indetermined // Well, no IWAD found.
} GameMode_t;
// Mission packs - might be useful for TC stuff?
typedef enum
{
doom, // DOOM 1
doom2, // DOOM 2
pack_tnt, // TNT mission pack
pack_plut, // Plutonia pack
none
} GameMission_t;
// Identify language to use, software localization.
typedef enum
{
english,
french,
german,
unknown
} Language_t;
// If rangecheck is undefined,
// most parameter validation debugging code will not be compiled
#define RANGECHECK
//
// For resize of screen, at start of game.
// It will not work dynamically, see visplanes.
//
#define BASE_WIDTH 320
// It is educational but futile to change this
// scaling e.g. to 2. Drawing of status bar,
// menues etc. is tied to the scale implied
// by the graphics.
#define SCREEN_MUL 1
#define INV_ASPECT_RATIO 0.625 // 0.75, ideally
// Defines suck. C sucks.
// C++ might sucks for OOP, but it sure is a better C.
// So there.
// extern int SCREENWIDTH;
#define SCREENWIDTH 320
#define SCREENHEIGHT 200
// The maximum number of players, multiplayer/networking.
#define MAXPLAYERS 4
// State updates, number of tics / second.
#if defined(DOOM_FAST_TICK)
#define TICKMUL 2
#else
#define TICKMUL 1
#endif
#define TICRATE (35 * TICKMUL)
// The current state of the game: whether we are
// playing, gazing at the intermission screen,
// the game final animation, or a demo.
typedef enum
{
GS_LEVEL,
GS_INTERMISSION,
GS_FINALE,
GS_DEMOSCREEN
} gamestate_t;
//
// Difficulty/skill settings/filters.
//
// Skill flags.
#define MTF_EASY 1
#define MTF_NORMAL 2
#define MTF_HARD 4
// Deaf monsters/do not react to sound.
#define MTF_AMBUSH 8
typedef enum
{
sk_baby,
sk_easy,
sk_medium,
sk_hard,
sk_nightmare
} skill_t;
//
// Key cards.
//
typedef enum
{
it_bluecard,
it_yellowcard,
it_redcard,
it_blueskull,
it_yellowskull,
it_redskull,
NUMCARDS
} card_t;
// The defined weapons,
// including a marker indicating
// user has not changed weapon.
typedef enum
{
wp_fist,
wp_pistol,
wp_shotgun,
wp_chaingun,
wp_missile,
wp_plasma,
wp_bfg,
wp_chainsaw,
wp_supershotgun,
NUMWEAPONS,
// No pending weapon change.
wp_nochange
} weapontype_t;
// Ammunition types defined.
typedef enum
{
am_clip, // Pistol / chaingun ammo.
am_shell, // Shotgun / double barreled shotgun.
am_cell, // Plasma rifle, BFG.
am_misl, // Missile launcher.
NUMAMMO,
am_noammo // Unlimited for chainsaw / fist.
} ammotype_t;
// Power up artifacts.
typedef enum
{
pw_invulnerability,
pw_strength,
pw_invisibility,
pw_ironfeet,
pw_allmap,
pw_infrared,
NUMPOWERS
} powertype_t;
//
// Power up durations,
// how many seconds till expiration,
// assuming TICRATE is 35 ticks/second.
//
typedef enum
{
INVULNTICS = (30 * TICRATE),
INVISTICS = (60 * TICRATE),
INFRATICS = (120 * TICRATE),
IRONTICS = (60 * TICRATE)
} powerduration_t;
//
// DOOM keyboard definition.
// This is the stuff configured by Setup.Exe.
// Most key data are simple ascii (uppercased).
//
#define KEY_RIGHTARROW 0xae
#define KEY_LEFTARROW 0xac
#define KEY_UPARROW 0xad
#define KEY_DOWNARROW 0xaf
#define KEY_ESCAPE 27
#define KEY_ENTER 13
#define KEY_TAB 9
#define KEY_F1 (0x80+0x3b)
#define KEY_F2 (0x80+0x3c)
#define KEY_F3 (0x80+0x3d)
#define KEY_F4 (0x80+0x3e)
#define KEY_F5 (0x80+0x3f)
#define KEY_F6 (0x80+0x40)
#define KEY_F7 (0x80+0x41)
#define KEY_F8 (0x80+0x42)
#define KEY_F9 (0x80+0x43)
#define KEY_F10 (0x80+0x44)
#define KEY_F11 (0x80+0x57)
#define KEY_F12 (0x80+0x58)
#define KEY_BACKSPACE 127
#define KEY_PAUSE 0xff
#define KEY_EQUALS 0x3d
#define KEY_MINUS 0x2d
#define KEY_RSHIFT (0x80+0x36)
#define KEY_RCTRL (0x80+0x1d)
#define KEY_RALT (0x80+0x38)
#define KEY_LALT KEY_RALT
#endif // __DOOMDEF__
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

37
src/DOOM/doomstat.c Normal file
View File

@ -0,0 +1,37 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Put all global tate variables here.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomstat.h"
// Game Mode - identify IWAD as shareware, retail etc.
GameMode_t gamemode = indetermined;
GameMission_t gamemission = doom;
// Language.
Language_t language = english;
// Set if homebrew PWAD stuff has been added.
doom_boolean modifiedgame;

268
src/DOOM/doomstat.h Normal file
View File

@ -0,0 +1,268 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// All the global variables that store the internal state.
// Theoretically speaking, the internal state of the engine
// should be found by looking at the variables collected
// here, and every relevant module will have to include
// this header file.
// In practice, things are a bit messy.
//
//-----------------------------------------------------------------------------
#ifndef __D_STATE__
#define __D_STATE__
// We need globally shared data structures,
// for defining the global state variables.
#include "doomdata.h"
#include "d_net.h"
// We need the playr data structure as well.
#include "d_player.h"
// ------------------------
// Command line parameters.
//
extern doom_boolean nomonsters; // checkparm of -nomonsters
extern doom_boolean respawnparm; // checkparm of -respawn
extern doom_boolean fastparm; // checkparm of -fast
extern doom_boolean devparm; // DEBUG: launched with -devparm
// -----------------------------------------------------
// Game Mode - identify IWAD as shareware, retail etc.
//
extern GameMode_t gamemode;
extern GameMission_t gamemission;
// Set if homebrew PWAD stuff has been added.
extern doom_boolean modifiedgame;
// -------------------------------------------
// Language.
extern Language_t language;
// -------------------------------------------
// Selected skill type, map etc.
//
// Defaults for menu, methinks.
extern skill_t startskill;
extern int startepisode;
extern int startmap;
extern doom_boolean autostart;
// Selected by user.
extern skill_t gameskill;
extern int gameepisode;
extern int gamemap;
// Nightmare mode flag, single player.
extern doom_boolean respawnmonsters;
// Netgame? Only true if >1 player.
extern doom_boolean netgame;
// Flag: true only if started as net deathmatch.
// An enum might handle altdeath/cooperative better.
extern doom_boolean deathmatch;
// -------------------------
// Internal parameters for sound rendering.
// These have been taken from the DOS version,
// but are not (yet) supported with Linux
// (e.g. no sound volume adjustment with menu.
// These are not used, but should be (menu).
// From m_menu.c:
// Sound FX volume has default, 0 - 15
// Music volume has default, 0 - 15
// These are multiplied by 8.
extern int snd_SfxVolume; // maximum volume for sound
extern int snd_MusicVolume; // maximum volume for music
// Current music/sfx card - index useless
// w/o a reference LUT in a sound module.
// Ideally, this would use indices found
// in: /usr/include/linux/soundcard.h
extern int snd_MusicDevice;
extern int snd_SfxDevice;
// Config file? Same disclaimer as above.
extern int snd_DesiredMusicDevice;
extern int snd_DesiredSfxDevice;
// -------------------------
// Status flags for refresh.
//
// Depending on view size - no status bar?
// Note that there is no way to disable the
// status bar explicitely.
extern doom_boolean statusbaractive;
extern doom_boolean automapactive; // In AutoMap mode?
extern doom_boolean menuactive; // Menu overlayed?
extern doom_boolean paused; // Game Pause?
extern doom_boolean viewactive;
extern doom_boolean nodrawers;
extern doom_boolean noblit;
extern int viewwindowx;
extern int viewwindowy;
extern int viewheight;
extern int viewwidth;
extern int scaledviewwidth;
// This one is related to the 3-screen display mode.
// ANG90 = left side, ANG270 = right
extern int viewangleoffset;
// Player taking events, and displaying.
extern int consoleplayer;
extern int displayplayer;
// -------------------------------------
// Scores, rating.
// Statistics on a given map, for intermission.
//
extern int totalkills;
extern int totalitems;
extern int totalsecret;
// Timer, for scores.
extern int levelstarttic; // gametic at level start
extern int leveltime; // tics in game play for par
// --------------------------------------
// DEMO playback/recording related stuff.
// No demo, there is a human player in charge?
// Disable save/end game?
extern doom_boolean usergame;
//?
extern doom_boolean demoplayback;
extern doom_boolean demorecording;
// Quit after playing a demo from cmdline.
extern doom_boolean singledemo;
//?
extern gamestate_t gamestate;
//-----------------------------
// Internal parameters, fixed.
// These are set by the engine, and not changed
// according to user inputs. Partly load from
// WAD, partly set at startup time.
extern int gametic;
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
// Alive? Disconnected?
extern doom_boolean playeringame[MAXPLAYERS];
// Player spawn spots for deathmatch.
#define MAX_DM_STARTS 10
extern mapthing_t deathmatchstarts[MAX_DM_STARTS];
extern mapthing_t* deathmatch_p;
// Player spawn spots.
extern mapthing_t playerstarts[MAXPLAYERS];
// Intermission stats.
// Parameters for world map / intermission.
extern wbstartstruct_t wminfo;
// LUT of ammunition limits for each kind.
// This doubles with BackPack powerup item.
extern int maxammo[NUMAMMO];
//-----------------------------------------
// Internal parameters, used for engine.
//
// File handling stuff.
extern char basedefault[1024];
extern void* debugfile;
// if true, load all graphics at level load
extern doom_boolean precache;
// wipegamestate can be set to -1
// to force a wipe on the next draw
extern gamestate_t wipegamestate;
extern int mouseSensitivity;
//?
// debug flag to cancel adaptiveness
extern doom_boolean singletics;
extern int bodyqueslot;
// Needed to store the number of the dummy sky flat.
// Used for rendering,
// as well as tracking projectiles etc.
extern int skyflatnum;
// Netgame stuff (buffers and pointers, i.e. indices).
// This is ???
extern doomcom_t* doomcom;
// This points inside doomcom.
extern doomdata_t* netbuffer;
extern ticcmd_t localcmds[BACKUPTICS];
extern int rndindex;
extern int maketic;
extern int nettics[MAXNETNODES];
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
extern int ticdup;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

65
src/DOOM/doomtype.h Normal file
View File

@ -0,0 +1,65 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Simple basic typedefs, isolated here to make it easier
// separating modules.
//
//-----------------------------------------------------------------------------
#ifndef __DOOMTYPE__
#define __DOOMTYPE__
// Fixed to use builtin bool type with C++.
#ifdef __cplusplus
typedef bool doom_boolean;
#else
#if !defined(false) && !defined(true)
typedef enum
{
false, true
} doom_boolean;
#else
typedef int doom_boolean;
#endif
#endif
typedef unsigned char byte;
#define DOOM_MAXCHAR ((char)0x7f)
#define DOOM_MAXSHORT ((short)0x7fff)
// Max pos 32-bit int.
#define DOOM_MAXINT ((int)0x7fffffff)
#define DOOM_MAXLONG ((long)0x7fffffff)
#define DOOM_MINCHAR ((char)0x80)
#define DOOM_MINSHORT ((short)0x8000)
// Max negative 32-bit integer.
#define DOOM_MININT ((int)0x80000000)
#define DOOM_MINLONG ((long)0x80000000)
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

61
src/DOOM/dstrings.c Normal file
View File

@ -0,0 +1,61 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Globally defined strings.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "dstrings.h"
char* endmsg[NUM_QUITMESSAGES + 1] =
{
// DOOM1
QUITMSG,
"please don't leave, there's more\ndemons to toast!",
"let's beat it -- this is turning\ninto a bloodbath!",
"i wouldn't leave if i were you.\ndos is much worse.",
"you're trying to say you like dos\nbetter than me, right?",
"don't leave yet -- there's a\ndemon around that corner!",
"ya know, next time you come in here\ni'm gonna toast ya.",
"go ahead and leave. see if i care.",
// QuitDOOM II messages
"you want to quit?\nthen, thou hast lost an eighth!",
"don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!",
"get outta here and go back\nto your boring programs.",
"if i were your boss, i'd \n deathmatch ya in a minute!",
"look, bud. you leave now\nand you forfeit your body count!",
"just leave. when you come\nback, i'll be waiting with a bat.",
"you're lucky i don't smack\nyou for thinking about leaving.",
// FinalDOOM?
"fuck you, pussy!\nget the fuck out!",
"you quit and i'll jizz\nin your cystholes!",
"if you leave, i'll make\nthe lord drink my jizz.",
"hey, ron! can we say\n'fuck' in the game?",
"i'd leave: this is just\nmore monsters and levels.\nwhat a load.",
"suck it down, asshole!\nyou're a fucking wimp!",
"don't quit now! we're \nstill spending your money!",
// Internal debug. Different style, too.
"THIS IS NO MESSAGE!\nPage intentionally left blank."
};

66
src/DOOM/dstrings.h Normal file
View File

@ -0,0 +1,66 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//
// $Log:$
//
// DESCRIPTION:
// DOOM strings, by language.
//
//-----------------------------------------------------------------------------
#ifndef __DSTRINGS__
#define __DSTRINGS__
// All important printed strings.
// Language selection (message strings).
// Use -DFRENCH etc.
#ifdef FRENCH
#include "d_french.h" // Leave the extra space there, to throw off regex in PureDOOM.h creation
#else
#include "d_englsh.h"
#endif
// Misc. other strings.
#define SAVEGAMENAME "doomsav"
//
// File locations,
// relative to current position.
// Path names are OS-sensitive.
//
#define DEVMAPS "devmaps"
#define DEVDATA "devdata"
// Not done in french?
// QuitDOOM messages
#define NUM_QUITMESSAGES 22
extern char* endmsg[];
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

718
src/DOOM/f_finale.c Normal file
View File

@ -0,0 +1,718 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Game completion, final screen animation.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "i_system.h" // Functions.
#include "m_swap.h" // Functions.
#include "z_zone.h" // Functions.
#include "v_video.h" // Functions.
#include "w_wad.h" // Functions.
#include "s_sound.h" // Functions.
#include "dstrings.h" // Data.
#include "sounds.h" // Data.
#include "doomstat.h"
#include "r_state.h"
#include "hu_stuff.h"
#define TEXTSPEED 3
#define TEXTWAIT 250
typedef struct
{
char* name;
mobjtype_t type;
} castinfo_t;
// Stage of animation:
// 0 = text, 1 = art screen, 2 = character cast
int finalestage;
int finalecount;
char* e1text = E1TEXT;
char* e2text = E2TEXT;
char* e3text = E3TEXT;
char* e4text = E4TEXT;
char* c1text = C1TEXT;
char* c2text = C2TEXT;
char* c3text = C3TEXT;
char* c4text = C4TEXT;
char* c5text = C5TEXT;
char* c6text = C6TEXT;
char* p1text = P1TEXT;
char* p2text = P2TEXT;
char* p3text = P3TEXT;
char* p4text = P4TEXT;
char* p5text = P5TEXT;
char* p6text = P6TEXT;
char* t1text = T1TEXT;
char* t2text = T2TEXT;
char* t3text = T3TEXT;
char* t4text = T4TEXT;
char* t5text = T5TEXT;
char* t6text = T6TEXT;
char* finaletext;
char* finaleflat;
castinfo_t castorder[] = {
{CC_ZOMBIE, MT_POSSESSED},
{CC_SHOTGUN, MT_SHOTGUY},
{CC_HEAVY, MT_CHAINGUY},
{CC_IMP, MT_TROOP},
{CC_DEMON, MT_SERGEANT},
{CC_LOST, MT_SKULL},
{CC_CACO, MT_HEAD},
{CC_HELL, MT_KNIGHT},
{CC_BARON, MT_BRUISER},
{CC_ARACH, MT_BABY},
{CC_PAIN, MT_PAIN},
{CC_REVEN, MT_UNDEAD},
{CC_MANCU, MT_FATSO},
{CC_ARCH, MT_VILE},
{CC_SPIDER, MT_SPIDER},
{CC_CYBER, MT_CYBORG},
{CC_HERO, MT_PLAYER},
{0,0}
};
int castnum;
int casttics;
state_t* caststate;
doom_boolean castdeath;
int castframes;
int castonmelee;
doom_boolean castattacking;
//
// F_StartCast
//
extern gamestate_t wipegamestate;
extern patch_t* hu_font[HU_FONTSIZE];
void F_StartCast(void);
void F_CastTicker(void);
doom_boolean F_CastResponder(event_t* ev);
void F_CastDrawer(void);
void V_DrawPatchFlipped(int x, int y, int scrn, patch_t* patch);
//
// F_StartFinale
//
void F_StartFinale(void)
{
gameaction = ga_nothing;
gamestate = GS_FINALE;
viewactive = false;
automapactive = false;
// Okay - IWAD dependend stuff.
// This has been changed severly, and
// some stuff might have changed in the process.
switch (gamemode)
{
// DOOM 1 - E1, E3 or E4, but each nine missions
case shareware:
case registered:
case retail:
{
S_ChangeMusic(mus_victor, true);
switch (gameepisode)
{
case 1:
finaleflat = "FLOOR4_8";
finaletext = e1text;
break;
case 2:
finaleflat = "SFLR6_1";
finaletext = e2text;
break;
case 3:
finaleflat = "MFLR8_4";
finaletext = e3text;
break;
case 4:
finaleflat = "MFLR8_3";
finaletext = e4text;
break;
default:
// Ouch.
break;
}
break;
}
// DOOM II and missions packs with E1, M34
case commercial:
{
S_ChangeMusic(mus_read_m, true);
switch (gamemap)
{
case 6:
finaleflat = "SLIME16";
finaletext = c1text;
break;
case 11:
finaleflat = "RROCK14";
finaletext = c2text;
break;
case 20:
finaleflat = "RROCK07";
finaletext = c3text;
break;
case 30:
finaleflat = "RROCK17";
finaletext = c4text;
break;
case 15:
finaleflat = "RROCK13";
finaletext = c5text;
break;
case 31:
finaleflat = "RROCK19";
finaletext = c6text;
break;
default:
// Ouch.
break;
}
break;
}
// Indeterminate.
default:
S_ChangeMusic(mus_read_m, true);
finaleflat = "F_SKY1"; // Not used anywhere else.
finaletext = c1text; // FIXME - other text, music?
break;
}
finalestage = 0;
finalecount = 0;
}
doom_boolean F_Responder(event_t* event)
{
if (finalestage == 2)
return F_CastResponder(event);
return false;
}
//
// F_Ticker
//
void F_Ticker(void)
{
int i;
// check for skipping
if ((gamemode == commercial)
&& (finalecount > 50))
{
// go on to the next level
for (i = 0; i < MAXPLAYERS; i++)
if (players[i].cmd.buttons)
break;
if (i < MAXPLAYERS)
{
if (gamemap == 30)
F_StartCast();
else
gameaction = ga_worlddone;
}
}
// advance animation
finalecount++;
if (finalestage == 2)
{
F_CastTicker();
return;
}
if (gamemode == commercial)
return;
if (!finalestage && finalecount > doom_strlen(finaletext) * TEXTSPEED + TEXTWAIT)
{
finalecount = 0;
finalestage = 1;
wipegamestate = -1; // force a wipe
if (gameepisode == 3)
S_StartMusic(mus_bunny);
}
}
//
// F_TextWrite
//
void F_TextWrite(void)
{
byte* src;
byte* dest;
int x, y, w;
int count;
char* ch;
int c;
int cx;
int cy;
// erase the entire screen to a tiled background
src = W_CacheLumpName(finaleflat, PU_CACHE);
dest = screens[0];
for (y = 0; y < SCREENHEIGHT; y++)
{
for (x = 0; x < SCREENWIDTH / 64; x++)
{
doom_memcpy(dest, src + ((y & 63) << 6), 64);
dest += 64;
}
if (SCREENWIDTH & 63)
{
doom_memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
dest += (SCREENWIDTH & 63);
}
}
V_MarkRect(0, 0, SCREENWIDTH, SCREENHEIGHT);
// draw some of the text onto the screen
cx = 10;
cy = 10;
ch = finaletext;
count = (finalecount - 10) / TEXTSPEED;
if (count < 0)
count = 0;
for (; count; count--)
{
c = *ch++;
if (!c)
break;
if (c == '\n')
{
cx = 10;
cy += 11;
continue;
}
c = doom_toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
cx += 4;
continue;
}
w = SHORT(hu_font[c]->width);
if (cx + w > SCREENWIDTH)
break;
V_DrawPatch(cx, cy, 0, hu_font[c]);
cx += w;
}
}
//
// Final DOOM 2 animation
// Casting by id Software.
// in order of appearance
//
void F_StartCast(void)
{
wipegamestate = -1; // force a screen wipe
castnum = 0;
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
casttics = caststate->tics;
castdeath = false;
finalestage = 2;
castframes = 0;
castonmelee = 0;
castattacking = false;
S_ChangeMusic(mus_evil, true);
}
//
// F_CastTicker
//
void F_CastTicker(void)
{
int st;
int sfx;
if (--casttics > 0)
return; // not time to change state yet
if (caststate->tics == -1 || caststate->nextstate == S_NULL)
{
// switch from deathstate to next monster
castnum++;
castdeath = false;
if (castorder[castnum].name == 0)
castnum = 0;
if (mobjinfo[castorder[castnum].type].seesound)
S_StartSound(0, mobjinfo[castorder[castnum].type].seesound);
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
castframes = 0;
}
else
{
// just advance to next state in animation
if (caststate == &states[S_PLAY_ATK1])
goto stopattack; // Oh, gross hack!
st = caststate->nextstate;
caststate = &states[st];
castframes++;
// sound hacks....
switch (st)
{
case S_PLAY_ATK1: sfx = sfx_dshtgn; break;
case S_POSS_ATK2: sfx = sfx_pistol; break;
case S_SPOS_ATK2: sfx = sfx_shotgn; break;
case S_VILE_ATK2: sfx = sfx_vilatk; break;
case S_SKEL_FIST2: sfx = sfx_skeswg; break;
case S_SKEL_FIST4: sfx = sfx_skepch; break;
case S_SKEL_MISS2: sfx = sfx_skeatk; break;
case S_FATT_ATK8:
case S_FATT_ATK5:
case S_FATT_ATK2: sfx = sfx_firsht; break;
case S_CPOS_ATK2:
case S_CPOS_ATK3:
case S_CPOS_ATK4: sfx = sfx_shotgn; break;
case S_TROO_ATK3: sfx = sfx_claw; break;
case S_SARG_ATK2: sfx = sfx_sgtatk; break;
case S_BOSS_ATK2:
case S_BOS2_ATK2:
case S_HEAD_ATK2: sfx = sfx_firsht; break;
case S_SKULL_ATK2: sfx = sfx_sklatk; break;
case S_SPID_ATK2:
case S_SPID_ATK3: sfx = sfx_shotgn; break;
case S_BSPI_ATK2: sfx = sfx_plasma; break;
case S_CYBER_ATK2:
case S_CYBER_ATK4:
case S_CYBER_ATK6: sfx = sfx_rlaunc; break;
case S_PAIN_ATK3: sfx = sfx_sklatk; break;
default: sfx = 0; break;
}
if (sfx)
S_StartSound(0, sfx);
}
if (castframes == 12)
{
// go into attack frame
castattacking = true;
if (castonmelee)
caststate = &states[mobjinfo[castorder[castnum].type].meleestate];
else
caststate = &states[mobjinfo[castorder[castnum].type].missilestate];
castonmelee ^= 1;
if (caststate == &states[S_NULL])
{
if (castonmelee)
caststate =
&states[mobjinfo[castorder[castnum].type].meleestate];
else
caststate =
&states[mobjinfo[castorder[castnum].type].missilestate];
}
}
if (castattacking)
{
if (castframes == 24
|| caststate == &states[mobjinfo[castorder[castnum].type].seestate])
{
stopattack:
castattacking = false;
castframes = 0;
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
}
}
casttics = caststate->tics;
if (casttics == -1)
casttics = 15;
}
//
// F_CastResponder
//
doom_boolean F_CastResponder(event_t* ev)
{
if (ev->type != ev_keydown)
return false;
if (castdeath)
return true; // already in dying frames
// go into death frame
castdeath = true;
caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
casttics = caststate->tics;
castframes = 0;
castattacking = false;
if (mobjinfo[castorder[castnum].type].deathsound)
S_StartSound(0, mobjinfo[castorder[castnum].type].deathsound);
return true;
}
void F_CastPrint(char* text)
{
char* ch;
int c;
int cx;
int w;
int width;
// find width
ch = text;
width = 0;
while (ch)
{
c = *ch++;
if (!c)
break;
c = doom_toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
width += 4;
continue;
}
w = SHORT(hu_font[c]->width);
width += w;
}
// draw it
cx = 160 - width / 2;
ch = text;
while (ch)
{
c = *ch++;
if (!c)
break;
c = doom_toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
cx += 4;
continue;
}
w = SHORT(hu_font[c]->width);
V_DrawPatch(cx, 180, 0, hu_font[c]);
cx += w;
}
}
//
// F_CastDrawer
//
void F_CastDrawer(void)
{
spritedef_t* sprdef;
spriteframe_t* sprframe;
int lump;
doom_boolean flip;
patch_t* patch;
// erase the entire screen to a background
V_DrawPatch(0, 0, 0, W_CacheLumpName("BOSSBACK", PU_CACHE));
F_CastPrint(castorder[castnum].name);
// draw the current frame in the middle of the screen
sprdef = &sprites[caststate->sprite];
sprframe = &sprdef->spriteframes[caststate->frame & FF_FRAMEMASK];
lump = sprframe->lump[0];
flip = (doom_boolean)sprframe->flip[0];
patch = W_CacheLumpNum(lump + firstspritelump, PU_CACHE);
if (flip)
V_DrawPatchFlipped(160, 170, 0, patch);
else
V_DrawPatch(160, 170, 0, patch);
}
//
// F_DrawPatchCol
//
void F_DrawPatchCol(int x, patch_t* patch, int col)
{
column_t* column;
byte* source;
byte* dest;
byte* desttop;
int count;
column = (column_t*)((byte*)patch + LONG(patch->columnofs[col]));
desttop = screens[0] + x;
// step through the posts in a column
while (column->topdelta != 0xff)
{
source = (byte*)column + 3;
dest = desttop + column->topdelta * SCREENWIDTH;
count = column->length;
while (count--)
{
*dest = *source++;
dest += SCREENWIDTH;
}
column = (column_t*)((byte*)column + column->length + 4);
}
}
//
// F_BunnyScroll
//
void F_BunnyScroll(void)
{
int scrolled;
int x;
patch_t* p1;
patch_t* p2;
char name[10];
int stage;
static int laststage;
p1 = W_CacheLumpName("PFUB2", PU_LEVEL);
p2 = W_CacheLumpName("PFUB1", PU_LEVEL);
V_MarkRect(0, 0, SCREENWIDTH, SCREENHEIGHT);
scrolled = 320 - (finalecount - 230) / 2;
if (scrolled > 320)
scrolled = 320;
if (scrolled < 0)
scrolled = 0;
for (x = 0; x < SCREENWIDTH; x++)
{
if (x + scrolled < 320)
F_DrawPatchCol(x, p1, x + scrolled);
else
F_DrawPatchCol(x, p2, x + scrolled - 320);
}
if (finalecount < 1130)
return;
if (finalecount < 1180)
{
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
(SCREENHEIGHT - 8 * 8) / 2, 0, W_CacheLumpName("END0", PU_CACHE));
laststage = 0;
return;
}
stage = (finalecount - 1180) / 5;
if (stage > 6)
stage = 6;
if (stage > laststage)
{
S_StartSound(0, sfx_pistol);
laststage = stage;
}
//doom_sprintf(name, "END%i", stage);
doom_strcpy(name, "END");
doom_concat(name, doom_itoa(stage, 10));
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2, 0, W_CacheLumpName(name, PU_CACHE));
}
//
// F_Drawer
//
void F_Drawer(void)
{
if (finalestage == 2)
{
F_CastDrawer();
return;
}
if (!finalestage)
F_TextWrite();
else
{
switch (gameepisode)
{
case 1:
if (gamemode == retail)
V_DrawPatch(0, 0, 0,
W_CacheLumpName("CREDIT", PU_CACHE));
else
V_DrawPatch(0, 0, 0,
W_CacheLumpName("HELP2", PU_CACHE));
break;
case 2:
V_DrawPatch(0, 0, 0,
W_CacheLumpName("VICTORY2", PU_CACHE));
break;
case 3:
F_BunnyScroll();
break;
case 4:
V_DrawPatch(0, 0, 0,
W_CacheLumpName("ENDPIC", PU_CACHE));
break;
}
}
}

52
src/DOOM/f_finale.h Normal file
View File

@ -0,0 +1,52 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __F_FINALE__
#define __F_FINALE__
#include "doomtype.h"
#include "d_event.h"
//
// FINALE
//
// Called by main loop.
doom_boolean F_Responder(event_t* ev);
// Called by main loop.
void F_Ticker(void);
// Called by main loop.
void F_Drawer(void);
void F_StartFinale(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

258
src/DOOM/f_wipe.c Normal file
View File

@ -0,0 +1,258 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Mission begin melt/wipe screen special effect.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "i_video.h"
#include "v_video.h"
#include "m_random.h"
#include "doomdef.h"
#include "f_wipe.h"
//
// SCREEN WIPE PACKAGE
//
// when zero, stop the wipe
static doom_boolean go = 0;
static byte* wipe_scr_start;
static byte* wipe_scr_end;
static byte* wipe_scr;
static int* y;
void wipe_shittyColMajorXform(short* array, int width, int height)
{
int x;
int y;
short* dest;
dest = (short*)Z_Malloc(width * height * sizeof(short), PU_STATIC, 0);
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
dest[x * height + y] = array[y * width + x];
doom_memcpy(array, dest, width * height * 2);
Z_Free(dest);
}
int wipe_initColorXForm(int width, int height, int ticks)
{
doom_memcpy(wipe_scr, wipe_scr_start, width * height);
return 0;
}
int wipe_doColorXForm(int width, int height, int ticks)
{
doom_boolean changed;
byte* w;
byte* e;
int newval;
changed = false;
w = wipe_scr;
e = wipe_scr_end;
while (w != wipe_scr + width * height)
{
if (*w != *e)
{
if (*w > *e)
{
newval = *w - ticks;
if (newval < *e)
*w = *e;
else
*w = newval;
changed = true;
}
else if (*w < *e)
{
newval = *w + ticks;
if (newval > *e)
*w = *e;
else
*w = newval;
changed = true;
}
}
w++;
e++;
}
return !changed;
}
int wipe_exitColorXForm(int width, int height, int ticks)
{
return 0;
}
int wipe_initMelt(int width, int height, int ticks)
{
int i, r;
// copy start screen to main screen
doom_memcpy(wipe_scr, wipe_scr_start, width * height);
// makes this wipe faster (in theory)
// to have stuff in column-major format
wipe_shittyColMajorXform((short*)wipe_scr_start, width / 2, height);
wipe_shittyColMajorXform((short*)wipe_scr_end, width / 2, height);
// setup initial column positions
// (y<0 => not ready to scroll yet)
y = (int*)Z_Malloc(width * sizeof(int), PU_STATIC, 0);
y[0] = -(M_Random() % 16);
for (i = 1; i < width; i++)
{
r = (M_Random() % 3) - 1;
y[i] = y[i - 1] + r;
if (y[i] > 0) y[i] = 0;
else if (y[i] == -16) y[i] = -15;
}
return 0;
}
int wipe_doMelt(int width, int height, int ticks)
{
int i;
int j;
int dy;
int idx;
short* s;
short* d;
doom_boolean done = true;
width /= 2;
while (ticks--)
{
for (i = 0; i < width; i++)
{
if (y[i] < 0)
{
y[i]++; done = false;
}
else if (y[i] < height)
{
dy = (y[i] < 16) ? y[i] + 1 : 8;
if (y[i] + dy >= height) dy = height - y[i];
s = &((short*)wipe_scr_end)[i * height + y[i]];
d = &((short*)wipe_scr)[y[i] * width + i];
idx = 0;
for (j = dy; j; j--)
{
d[idx] = *(s++);
idx += width;
}
y[i] += dy;
s = &((short*)wipe_scr_start)[i * height];
d = &((short*)wipe_scr)[y[i] * width + i];
idx = 0;
for (j = height - y[i]; j; j--)
{
d[idx] = *(s++);
idx += width;
}
done = false;
}
}
}
return done;
}
int wipe_exitMelt(int width, int height, int ticks)
{
Z_Free(y);
return 0;
}
int wipe_StartScreen(int x, int y, int width, int height)
{
wipe_scr_start = screens[2];
I_ReadScreen(wipe_scr_start);
return 0;
}
int wipe_EndScreen(int x, int y, int width, int height)
{
wipe_scr_end = screens[3];
I_ReadScreen(wipe_scr_end);
V_DrawBlock(x, y, 0, width, height, wipe_scr_start); // restore start scr.
return 0;
}
int wipe_ScreenWipe(int wipeno, int x, int y, int width, int height, int ticks)
{
int rc;
static int (*wipes[])(int, int, int) =
{
wipe_initColorXForm, wipe_doColorXForm, wipe_exitColorXForm,
wipe_initMelt, wipe_doMelt, wipe_exitMelt
};
void V_MarkRect(int, int, int, int);
// initial stuff
if (!go)
{
go = 1;
// wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG
wipe_scr = screens[0];
(*wipes[wipeno * 3])(width, height, ticks);
}
// do a piece of wipe-in
V_MarkRect(0, 0, width, height);
rc = (*wipes[wipeno * 3 + 1])(width, height, ticks);
// V_DrawBlock(x, y, 0, width, height, wipe_scr); // DEBUG
// final stuff
if (rc)
{
go = 0;
(*wipes[wipeno * 3 + 2])(width, height, ticks);
}
return !go;
}

53
src/DOOM/f_wipe.h Normal file
View File

@ -0,0 +1,53 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Mission start screen wipe/melt, special effects.
//
//-----------------------------------------------------------------------------
#ifndef __F_WIPE_H__
#define __F_WIPE_H__
//
// SCREEN WIPE PACKAGE
//
enum
{
// simple gradual pixel change for 8-bit only
wipe_ColorXForm,
// weird screen melt
wipe_Melt,
wipe_NUMWIPES
};
int wipe_StartScreen(int x, int y, int width, int height);
int wipe_EndScreen(int x, int y, int width, int height);
int wipe_ScreenWipe(int wipeno, int x, int y, int width, int height, int ticks);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

1678
src/DOOM/g_game.c Normal file

File diff suppressed because it is too large Load Diff

78
src/DOOM/g_game.h Normal file
View File

@ -0,0 +1,78 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Duh.
//
//-----------------------------------------------------------------------------
#ifndef __G_GAME__
#define __G_GAME__
#include "doomdef.h"
#include "d_event.h"
//
// GAME
//
void G_DeathMatchSpawnPlayer(int playernum);
void G_InitNew(skill_t skill, int episode, int map);
// Can be called by the startup code or M_Responder.
// A normal game starts at map 1,
// but a warp test can start elsewhere
void G_DeferedInitNew(skill_t skill, int episode, int map);
void G_DeferedPlayDemo(char* demo);
// Can be called by the startup code or M_Responder,
// calls P_SetupLevel or W_EnterWorld.
void G_LoadGame(char* name);
void G_DoLoadGame(void);
// Called by M_Responder.
void G_SaveGame(int slot, char* description);
// Only called by startup code.
void G_RecordDemo(char* name);
void G_BeginRecording(void);
void G_TimeDemo(char* name);
doom_boolean G_CheckDemoStatus(void);
void G_ExitLevel(void);
void G_SecretExitLevel(void);
void G_WorldDone(void);
void G_Ticker(void);
doom_boolean G_Responder(event_t* ev);
void G_ScreenShot(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

329
src/DOOM/hu_lib.c Normal file
View File

@ -0,0 +1,329 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION: heads-up text and input code
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "v_video.h"
#include "m_swap.h"
#include "hu_lib.h"
#include "r_local.h"
#include "r_draw.h"
// doom_boolean : whether the screen is always erased
#define noterased viewwindowx
extern doom_boolean automapactive; // in AM_map.c
void HUlib_init(void)
{
}
void HUlib_clearTextLine(hu_textline_t* t)
{
t->len = 0;
t->l[0] = 0;
t->needsupdate = true;
}
void HUlib_initTextLine(hu_textline_t* t, int x, int y, patch_t** f, int sc)
{
t->x = x;
t->y = y;
t->f = f;
t->sc = sc;
HUlib_clearTextLine(t);
}
doom_boolean HUlib_addCharToTextLine(hu_textline_t* t, char ch)
{
if (t->len == HU_MAXLINELENGTH)
return false;
else
{
t->l[t->len++] = ch;
t->l[t->len] = 0;
t->needsupdate = 4;
return true;
}
}
doom_boolean HUlib_delCharFromTextLine(hu_textline_t* t)
{
if (!t->len) return false;
else
{
t->l[--t->len] = 0;
t->needsupdate = 4;
return true;
}
}
void HUlib_drawTextLine(hu_textline_t* l, doom_boolean drawcursor)
{
int i;
int w;
int x;
unsigned char c;
// draw the new stuff
x = l->x;
for (i = 0; i < l->len; i++)
{
c = doom_toupper(l->l[i]);
if (c != ' '
&& c >= l->sc
&& c <= '_')
{
w = SHORT(l->f[c - l->sc]->width);
if (x + w > SCREENWIDTH)
break;
V_DrawPatchDirect(x, l->y, FG, l->f[c - l->sc]);
x += w;
}
else
{
x += 4;
if (x >= SCREENWIDTH)
break;
}
}
// draw the cursor if requested
if (drawcursor
&& x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH)
{
V_DrawPatchDirect(x, l->y, FG, l->f['_' - l->sc]);
}
}
// sorta called by HU_Erase and just better darn get things straight
void HUlib_eraseTextLine(hu_textline_t* l)
{
int lh;
int y;
int yoffset;
static doom_boolean lastautomapactive = true;
// Only erases when NOT in automap and the screen is reduced,
// and the text must either need updating or refreshing
// (because of a recent change back from the automap)
if (!automapactive &&
viewwindowx && l->needsupdate)
{
lh = SHORT(l->f[0]->height) + 1;
for (y = l->y, yoffset = y * SCREENWIDTH; y < l->y + lh; y++, yoffset += SCREENWIDTH)
{
if (y < viewwindowy || y >= viewwindowy + viewheight)
R_VideoErase(yoffset, SCREENWIDTH); // erase entire line
else
{
R_VideoErase(yoffset, viewwindowx); // erase left border
R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
// erase right border
}
}
}
lastautomapactive = automapactive;
if (l->needsupdate) l->needsupdate--;
}
void HUlib_initSText(hu_stext_t* s,
int x,
int y,
int h,
patch_t** font,
int startchar,
doom_boolean* on)
{
int i;
s->h = h;
s->on = on;
s->laston = true;
s->cl = 0;
for (i = 0; i < h; i++)
HUlib_initTextLine(&s->l[i],
x, y - i * (SHORT(font[0]->height) + 1),
font, startchar);
}
void HUlib_addLineToSText(hu_stext_t* s)
{
int i;
// add a clear line
if (++s->cl == s->h)
s->cl = 0;
HUlib_clearTextLine(&s->l[s->cl]);
// everything needs updating
for (i = 0; i < s->h; i++)
s->l[i].needsupdate = 4;
}
void HUlib_addMessageToSText(hu_stext_t* s, char* prefix, char* msg)
{
HUlib_addLineToSText(s);
if (prefix)
while (*prefix)
HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++));
while (*msg)
HUlib_addCharToTextLine(&s->l[s->cl], *(msg++));
}
void HUlib_drawSText(hu_stext_t* s)
{
int i, idx;
hu_textline_t* l;
if (!*s->on)
return; // if not on, don't draw
// draw everything
for (i = 0; i < s->h; i++)
{
idx = s->cl - i;
if (idx < 0)
idx += s->h; // handle queue of lines
l = &s->l[idx];
// need a decision made here on whether to skip the draw
HUlib_drawTextLine(l, false); // no cursor, please
}
}
void HUlib_eraseSText(hu_stext_t* s)
{
int i;
for (i = 0; i < s->h; i++)
{
if (s->laston && !*s->on)
s->l[i].needsupdate = 4;
HUlib_eraseTextLine(&s->l[i]);
}
s->laston = *s->on;
}
void HUlib_initIText(hu_itext_t* it,
int x,
int y,
patch_t** font,
int startchar,
doom_boolean* on)
{
it->lm = 0; // default left margin is start of text
it->on = on;
it->laston = true;
HUlib_initTextLine(&it->l, x, y, font, startchar);
}
// The following deletion routines adhere to the left margin restriction
void HUlib_delCharFromIText(hu_itext_t* it)
{
if (it->l.len != it->lm)
HUlib_delCharFromTextLine(&it->l);
}
void HUlib_eraseLineFromIText(hu_itext_t* it)
{
while (it->lm != it->l.len)
HUlib_delCharFromTextLine(&it->l);
}
// Resets left margin as well
void HUlib_resetIText(hu_itext_t* it)
{
it->lm = 0;
HUlib_clearTextLine(&it->l);
}
void HUlib_addPrefixToIText(hu_itext_t* it, char* str)
{
while (*str)
HUlib_addCharToTextLine(&it->l, *(str++));
it->lm = it->l.len;
}
// wrapper function for handling general keyed input.
// returns true if it ate the key
doom_boolean HUlib_keyInIText(hu_itext_t* it, unsigned char ch)
{
if (ch >= ' ' && ch <= '_')
HUlib_addCharToTextLine(&it->l, (char)ch);
else
if (ch == KEY_BACKSPACE)
HUlib_delCharFromIText(it);
else
if (ch != KEY_ENTER)
return false; // did not eat key
return true; // ate the key
}
void HUlib_drawIText(hu_itext_t* it)
{
hu_textline_t* l = &it->l;
if (!*it->on)
return;
HUlib_drawTextLine(l, true); // draw the line w/ cursor
}
void HUlib_eraseIText(hu_itext_t* it)
{
if (it->laston && !*it->on)
it->l.needsupdate = 4;
HUlib_eraseTextLine(&it->l);
it->laston = *it->on;
}

181
src/DOOM/hu_lib.h Normal file
View File

@ -0,0 +1,181 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION: none
//
//-----------------------------------------------------------------------------
#ifndef __HULIB__
#define __HULIB__
// We are referring to patches.
#include "r_defs.h"
// background and foreground screen numbers
// different from other modules.
#define BG 1
#define FG 0
// font stuff
#define HU_CHARERASE KEY_BACKSPACE
#define HU_MAXLINES 4
#define HU_MAXLINELENGTH 80
//
// Typedefs of widgets
//
// Text Line widget
// (parent of Scrolling Text and Input Text widgets)
typedef struct
{
// left-justified position of scrolling text window
int x;
int y;
patch_t** f; // font
int sc; // start character
char l[HU_MAXLINELENGTH + 1]; // line of text
int len; // current line length
// whether this line needs to be udpated
int needsupdate;
} hu_textline_t;
// Scrolling Text window widget
// (child of Text Line widget)
typedef struct
{
hu_textline_t l[HU_MAXLINES]; // text lines to draw
int h; // height in lines
int cl; // current line number
// pointer to doom_boolean stating whether to update window
doom_boolean* on;
doom_boolean laston; // last value of *->on.
} hu_stext_t;
// Input Text Line widget
// (child of Text Line widget)
typedef struct
{
hu_textline_t l; // text line to input on
// left margin past which I am not to delete characters
int lm;
// pointer to doom_boolean stating whether to update window
doom_boolean* on;
doom_boolean laston; // last value of *->on;
} hu_itext_t;
//
// Widget creation, access, and update routines
//
// initializes heads-up widget library
void HUlib_init(void);
//
// textline code
//
// clear a line of text
void HUlib_clearTextLine(hu_textline_t* t);
void HUlib_initTextLine(hu_textline_t* t, int x, int y, patch_t** f, int sc);
// returns success
doom_boolean HUlib_addCharToTextLine(hu_textline_t* t, char ch);
// returns success
doom_boolean HUlib_delCharFromTextLine(hu_textline_t* t);
// draws tline
void HUlib_drawTextLine(hu_textline_t* l, doom_boolean drawcursor);
// erases text line
void HUlib_eraseTextLine(hu_textline_t* l);
//
// Scrolling Text window widget routines
//
// ?
void HUlib_initSText(hu_stext_t* s,
int x,
int y,
int h,
patch_t** font,
int startchar,
doom_boolean* on);
// add a new line
void HUlib_addLineToSText(hu_stext_t* s);
// ?
void HUlib_addMessageToSText(hu_stext_t* s, char* prefix, char* msg);
// draws stext
void HUlib_drawSText(hu_stext_t* s);
// erases all stext lines
void HUlib_eraseSText(hu_stext_t* s);
// Input Text Line widget routines
void HUlib_initIText(hu_itext_t* it,
int x,
int y,
patch_t** font,
int startchar,
doom_boolean* on);
// enforces left margin
void HUlib_delCharFromIText(hu_itext_t* it);
// enforces left margin
void HUlib_eraseLineFromIText(hu_itext_t* it);
// resets line and left margin
void HUlib_resetIText(hu_itext_t* it);
// left of left-margin
void HUlib_addPrefixToIText(hu_itext_t* it, char* str);
// whether eaten
doom_boolean HUlib_keyInIText(hu_itext_t* it, unsigned char ch);
void HUlib_drawIText(hu_itext_t* it);
// erases all itext lines
void HUlib_eraseIText(hu_itext_t* it);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

733
src/DOOM/hu_stuff.c Normal file
View File

@ -0,0 +1,733 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION: Heads-up displays
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "z_zone.h"
#include "m_swap.h"
#include "hu_stuff.h"
#include "hu_lib.h"
#include "w_wad.h"
#include "s_sound.h"
#include "doomstat.h"
#include "dstrings.h" // Data.
#include "sounds.h"
//
// Locally used constants, shortcuts.
//
#define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1])
#define HU_TITLE2 (mapnames2[gamemap-1])
#define HU_TITLEP (mapnamesp[gamemap-1])
#define HU_TITLET (mapnamest[gamemap-1])
#define HU_TITLEHEIGHT 1
#define HU_TITLEX 0
#define HU_TITLEY (167 - SHORT(hu_font[0]->height))
#define HU_INPUTTOGGLE 't'
#define HU_INPUTX HU_MSGX
#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1))
#define HU_INPUTWIDTH 64
#define HU_INPUTHEIGHT 1
#define QUEUESIZE 128
static player_t* plr;
static hu_textline_t w_title;
static hu_itext_t w_chat;
static doom_boolean always_off = false;
static char chat_dest[MAXPLAYERS];
static hu_itext_t w_inputbuffer[MAXPLAYERS];
static doom_boolean message_on;
static doom_boolean message_nottobefuckedwith;
static hu_stext_t w_message;
static int message_counter;
static doom_boolean headsupactive = false;
static char chatchars[QUEUESIZE];
static int head = 0;
static int tail = 0;
char* chat_macros[] =
{
HUSTR_CHATMACRO0,
HUSTR_CHATMACRO1,
HUSTR_CHATMACRO2,
HUSTR_CHATMACRO3,
HUSTR_CHATMACRO4,
HUSTR_CHATMACRO5,
HUSTR_CHATMACRO6,
HUSTR_CHATMACRO7,
HUSTR_CHATMACRO8,
HUSTR_CHATMACRO9
};
char* player_names[] =
{
HUSTR_PLRGREEN,
HUSTR_PLRINDIGO,
HUSTR_PLRBROWN,
HUSTR_PLRRED
};
const char* shiftxform;
const char french_shiftxform[] =
{
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31,
' ', '!', '"', '#', '$', '%', '&',
'"', // shift-'
'(', ')', '*', '+',
'?', // shift-,
'_', // shift--
'>', // shift-.
'?', // shift-/
'0', // shift-0
'1', // shift-1
'2', // shift-2
'3', // shift-3
'4', // shift-4
'5', // shift-5
'6', // shift-6
'7', // shift-7
'8', // shift-8
'9', // shift-9
'/',
'.', // shift-;
'<',
'+', // shift-=
'>', '?', '@',
'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',
'[', // shift-[
'!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
']', // shift-]
'"', '_',
'\'', // shift-`
'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',
'{', '|', '}', '~', 127
};
const char english_shiftxform[] =
{
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31,
' ', '!', '"', '#', '$', '%', '&',
'"', // shift-'
'(', ')', '*', '+',
'<', // shift-,
'_', // shift--
'>', // shift-.
'?', // shift-/
')', // shift-0
'!', // shift-1
'@', // shift-2
'#', // shift-3
'$', // shift-4
'%', // shift-5
'^', // shift-6
'&', // shift-7
'*', // shift-8
'(', // shift-9
':',
':', // shift-;
'<',
'+', // shift-=
'>', '?', '@',
'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',
'[', // shift-[
'!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
']', // shift-]
'"', '_',
'\'', // shift-`
'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',
'{', '|', '}', '~', 127
};
char frenchKeyMap[128] =
{
0,
1,2,3,4,5,6,7,8,9,10,
11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,
31,
' ','!','"','#','$','%','&','%','(',')','*','+',';','-',':','!',
'0','1','2','3','4','5','6','7','8','9',':','M','<','=','>','?',
'@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^','_',
'@','Q','B','C','D','E','F','G','H','I','J','K','L',',','N','O',
'P','A','R','S','T','U','V','Z','X','Y','W','^','\\','$','^',127
};
char chat_char; // remove later.
patch_t* hu_font[HU_FONTSIZE];
doom_boolean chat_on;
doom_boolean message_dontfuckwithme;
extern int showMessages;
extern doom_boolean automapactive;
//
// Builtin map names.
// The actual names can be found in DStrings.h.
//
char* mapnames[] = // DOOM shareware/registered/retail (Ultimate) names.
{
HUSTR_E1M1,
HUSTR_E1M2,
HUSTR_E1M3,
HUSTR_E1M4,
HUSTR_E1M5,
HUSTR_E1M6,
HUSTR_E1M7,
HUSTR_E1M8,
HUSTR_E1M9,
HUSTR_E2M1,
HUSTR_E2M2,
HUSTR_E2M3,
HUSTR_E2M4,
HUSTR_E2M5,
HUSTR_E2M6,
HUSTR_E2M7,
HUSTR_E2M8,
HUSTR_E2M9,
HUSTR_E3M1,
HUSTR_E3M2,
HUSTR_E3M3,
HUSTR_E3M4,
HUSTR_E3M5,
HUSTR_E3M6,
HUSTR_E3M7,
HUSTR_E3M8,
HUSTR_E3M9,
HUSTR_E4M1,
HUSTR_E4M2,
HUSTR_E4M3,
HUSTR_E4M4,
HUSTR_E4M5,
HUSTR_E4M6,
HUSTR_E4M7,
HUSTR_E4M8,
HUSTR_E4M9,
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL"
};
char* mapnames2[] = // DOOM 2 map names.
{
HUSTR_1,
HUSTR_2,
HUSTR_3,
HUSTR_4,
HUSTR_5,
HUSTR_6,
HUSTR_7,
HUSTR_8,
HUSTR_9,
HUSTR_10,
HUSTR_11,
HUSTR_12,
HUSTR_13,
HUSTR_14,
HUSTR_15,
HUSTR_16,
HUSTR_17,
HUSTR_18,
HUSTR_19,
HUSTR_20,
HUSTR_21,
HUSTR_22,
HUSTR_23,
HUSTR_24,
HUSTR_25,
HUSTR_26,
HUSTR_27,
HUSTR_28,
HUSTR_29,
HUSTR_30,
HUSTR_31,
HUSTR_32
};
char* mapnamesp[] = // Plutonia WAD map names.
{
PHUSTR_1,
PHUSTR_2,
PHUSTR_3,
PHUSTR_4,
PHUSTR_5,
PHUSTR_6,
PHUSTR_7,
PHUSTR_8,
PHUSTR_9,
PHUSTR_10,
PHUSTR_11,
PHUSTR_12,
PHUSTR_13,
PHUSTR_14,
PHUSTR_15,
PHUSTR_16,
PHUSTR_17,
PHUSTR_18,
PHUSTR_19,
PHUSTR_20,
PHUSTR_21,
PHUSTR_22,
PHUSTR_23,
PHUSTR_24,
PHUSTR_25,
PHUSTR_26,
PHUSTR_27,
PHUSTR_28,
PHUSTR_29,
PHUSTR_30,
PHUSTR_31,
PHUSTR_32
};
char* mapnamest[] = // TNT WAD map names.
{
THUSTR_1,
THUSTR_2,
THUSTR_3,
THUSTR_4,
THUSTR_5,
THUSTR_6,
THUSTR_7,
THUSTR_8,
THUSTR_9,
THUSTR_10,
THUSTR_11,
THUSTR_12,
THUSTR_13,
THUSTR_14,
THUSTR_15,
THUSTR_16,
THUSTR_17,
THUSTR_18,
THUSTR_19,
THUSTR_20,
THUSTR_21,
THUSTR_22,
THUSTR_23,
THUSTR_24,
THUSTR_25,
THUSTR_26,
THUSTR_27,
THUSTR_28,
THUSTR_29,
THUSTR_30,
THUSTR_31,
THUSTR_32
};
char ForeignTranslation(unsigned char ch)
{
return ch < 128 ? frenchKeyMap[ch] : ch;
}
void HU_Init(void)
{
int i;
int j;
char buffer[9];
if (french)
shiftxform = french_shiftxform;
else
shiftxform = english_shiftxform;
// load the heads-up font
j = HU_FONTSTART;
for (i = 0; i < HU_FONTSIZE; i++)
{
//if (j == 40) __debugbreak();
//doom_sprintf(buffer, "STCFN%.3d", j++);
doom_strcpy(buffer, "STCFN");
if (j < 100) doom_concat(buffer, "0");
if (j < 10) doom_concat(buffer, "0");
doom_concat(buffer, doom_itoa(j++, 10));
hu_font[i] = (patch_t*)W_CacheLumpName(buffer, PU_STATIC);
}
}
void HU_Stop(void)
{
headsupactive = false;
}
void HU_Start(void)
{
int i;
char* s;
if (headsupactive)
HU_Stop();
plr = &players[consoleplayer];
message_on = false;
message_dontfuckwithme = false;
message_nottobefuckedwith = false;
chat_on = false;
// create the message widget
HUlib_initSText(&w_message,
HU_MSGX, HU_MSGY, HU_MSGHEIGHT,
hu_font,
HU_FONTSTART, &message_on);
// create the map title widget
HUlib_initTextLine(&w_title,
HU_TITLEX, HU_TITLEY,
hu_font,
HU_FONTSTART);
switch (gamemode)
{
case shareware:
case registered:
case retail:
s = HU_TITLE;
break;
/* FIXME
case pack_plut:
s = HU_TITLEP;
break;
case pack_tnt:
s = HU_TITLET;
break;
*/
case commercial:
default:
s = HU_TITLE2;
break;
}
while (*s)
HUlib_addCharToTextLine(&w_title, *(s++));
// create the chat widget
HUlib_initIText(&w_chat,
HU_INPUTX, HU_INPUTY,
hu_font,
HU_FONTSTART, &chat_on);
// create the inputbuffer widgets
for (i = 0; i < MAXPLAYERS; i++)
HUlib_initIText(&w_inputbuffer[i], 0, 0, 0, 0, &always_off);
headsupactive = true;
}
void HU_Drawer(void)
{
HUlib_drawSText(&w_message);
HUlib_drawIText(&w_chat);
if (automapactive)
HUlib_drawTextLine(&w_title, false);
}
void HU_Erase(void)
{
HUlib_eraseSText(&w_message);
HUlib_eraseIText(&w_chat);
HUlib_eraseTextLine(&w_title);
}
void HU_Ticker(void)
{
int i, rc;
char c;
// tick down message counter if message is up
if (message_counter && !--message_counter)
{
message_on = false;
message_nottobefuckedwith = false;
}
if (showMessages || message_dontfuckwithme)
{
// display message if necessary
if ((plr->message && !message_nottobefuckedwith)
|| (plr->message && message_dontfuckwithme))
{
HUlib_addMessageToSText(&w_message, 0, plr->message);
plr->message = 0;
message_on = true;
message_counter = HU_MSGTIMEOUT;
message_nottobefuckedwith = message_dontfuckwithme;
message_dontfuckwithme = 0;
}
} // else message_on = false;
// check for incoming chat characters
if (netgame)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (i != consoleplayer
&& (c = players[i].cmd.chatchar))
{
if (c <= HU_BROADCAST)
chat_dest[i] = c;
else
{
if (c >= 'a' && c <= 'z')
c = (char)shiftxform[(unsigned char)c];
rc = HUlib_keyInIText(&w_inputbuffer[i], c);
if (rc && c == KEY_ENTER)
{
if (w_inputbuffer[i].l.len
&& (chat_dest[i] == consoleplayer + 1
|| chat_dest[i] == HU_BROADCAST))
{
HUlib_addMessageToSText(&w_message,
player_names[i],
w_inputbuffer[i].l.l);
message_nottobefuckedwith = true;
message_on = true;
message_counter = HU_MSGTIMEOUT;
if (gamemode == commercial)
S_StartSound(0, sfx_radio);
else
S_StartSound(0, sfx_tink);
}
HUlib_resetIText(&w_inputbuffer[i]);
}
}
players[i].cmd.chatchar = 0;
}
}
}
}
void HU_queueChatChar(char c)
{
if (((head + 1) & (QUEUESIZE - 1)) == tail)
{
plr->message = HUSTR_MSGU;
}
else
{
chatchars[head] = c;
head = (head + 1) & (QUEUESIZE - 1);
}
}
char HU_dequeueChatChar(void)
{
char c;
if (head != tail)
{
c = chatchars[tail];
tail = (tail + 1) & (QUEUESIZE - 1);
}
else
{
c = 0;
}
return c;
}
doom_boolean HU_Responder(event_t* ev)
{
static char lastmessage[HU_MAXLINELENGTH + 1];
char* macromessage;
doom_boolean eatkey = false;
static doom_boolean shiftdown = false;
static doom_boolean altdown = false;
unsigned char c;
int i;
int numplayers;
static char destination_keys[MAXPLAYERS] =
{
HUSTR_KEYGREEN,
HUSTR_KEYINDIGO,
HUSTR_KEYBROWN,
HUSTR_KEYRED
};
static int num_nobrainers = 0;
numplayers = 0;
for (i = 0; i < MAXPLAYERS; i++)
numplayers += playeringame[i];
if (ev->data1 == KEY_RSHIFT)
{
shiftdown = ev->type == ev_keydown;
return false;
}
else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
{
altdown = ev->type == ev_keydown;
return false;
}
if (ev->type != ev_keydown)
return false;
if (!chat_on)
{
if (ev->data1 == HU_MSGREFRESH)
{
message_on = true;
message_counter = HU_MSGTIMEOUT;
eatkey = true;
}
else if (netgame && ev->data1 == HU_INPUTTOGGLE)
{
eatkey = chat_on = true;
HUlib_resetIText(&w_chat);
HU_queueChatChar(HU_BROADCAST);
}
else if (netgame && numplayers > 2)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (ev->data1 == destination_keys[i])
{
if (playeringame[i] && i != consoleplayer)
{
eatkey = chat_on = true;
HUlib_resetIText(&w_chat);
HU_queueChatChar(i + 1);
break;
}
else if (i == consoleplayer)
{
num_nobrainers++;
if (num_nobrainers < 3)
plr->message = HUSTR_TALKTOSELF1;
else if (num_nobrainers < 6)
plr->message = HUSTR_TALKTOSELF2;
else if (num_nobrainers < 9)
plr->message = HUSTR_TALKTOSELF3;
else if (num_nobrainers < 32)
plr->message = HUSTR_TALKTOSELF4;
else
plr->message = HUSTR_TALKTOSELF5;
}
}
}
}
}
else
{
c = ev->data1;
// send a macro
if (altdown)
{
c = c - '0';
if (c > 9)
return false;
macromessage = chat_macros[c];
// kill last message with a '\n'
HU_queueChatChar(KEY_ENTER); // DEBUG!!!
// send the macro message
while (*macromessage)
HU_queueChatChar(*macromessage++);
HU_queueChatChar(KEY_ENTER);
// leave chat mode and notify that it was sent
chat_on = false;
doom_strcpy(lastmessage, chat_macros[c]);
plr->message = lastmessage;
eatkey = true;
}
else
{
if (french)
c = ForeignTranslation(c);
if (shiftdown || (c >= 'a' && c <= 'z'))
c = shiftxform[c];
eatkey = HUlib_keyInIText(&w_chat, c);
if (eatkey)
{
HU_queueChatChar(c);
}
if (c == KEY_ENTER)
{
chat_on = false;
if (w_chat.l.len)
{
doom_strcpy(lastmessage, w_chat.l.l);
plr->message = lastmessage;
}
}
else if (c == KEY_ESCAPE)
chat_on = false;
}
}
return eatkey;
}

67
src/DOOM/hu_stuff.h Normal file
View File

@ -0,0 +1,67 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION: Head up display
//
//-----------------------------------------------------------------------------
#ifndef __HU_STUFF_H__
#define __HU_STUFF_H__
#include "d_event.h"
//
// Globally visible constants.
//
#define HU_FONTSTART '!' // the first font characters
#define HU_FONTEND '_' // the last font characters
// Calculate # of glyphs in font.
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
#define HU_BROADCAST 5
#define HU_MSGREFRESH KEY_ENTER
#define HU_MSGX 0
#define HU_MSGY 0
#define HU_MSGWIDTH 64 // in characters
#define HU_MSGHEIGHT 1 // in lines
#define HU_MSGTIMEOUT (4*TICRATE)
//
// HEADS UP TEXT
//
void HU_Init(void);
void HU_Start(void);
doom_boolean HU_Responder(event_t* ev);
void HU_Ticker(void);
void HU_Drawer(void);
char HU_dequeueChatChar(void);
void HU_Erase(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

457
src/DOOM/i_net.c Normal file
View File

@ -0,0 +1,457 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//
//-----------------------------------------------------------------------------
//#define I_NET_ENABLED
#if defined(I_NET_ENABLED)
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
#include "doom_config.h"
#if defined(I_NET_ENABLED)
#if defined(DOOM_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <winsock.h>
#define IPPORT_USERRESERVED 5000
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#define SOCKET int
#endif
#else
#define IPPORT_USERRESERVED 5000
#endif
#include "i_system.h"
#include "d_event.h"
#include "d_net.h"
#include "m_argv.h"
#include "doomstat.h"
#include "i_net.h"
// For some odd reason...
#if !defined(DOOM_APPLE) // It doesn't complain on Win32? O_o
#define ntohl(x) \
((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
(((unsigned long int)(x) & 0x0000ff00U) << 8) | \
(((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
(((unsigned long int)(x) & 0xff000000U) >> 24)))
#define ntohs(x) \
((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
(((unsigned short int)(x) & 0xff00) >> 8))) \
#define htonl(x) ntohl(x)
#define htons(x) ntohs(x)
#endif
//
// NETWORKING
//
int DOOMPORT = (IPPORT_USERRESERVED + 0x1d);
int DOOMPORT_SEND = (IPPORT_USERRESERVED + 0x1e);
#if defined(I_NET_ENABLED)
SOCKET sendsocket;
SOCKET insocket;
struct sockaddr_in sendaddress[MAXNETNODES];
#endif
void (*netget) (void);
void (*netsend) (void);
void NetSend(void);
doom_boolean NetListen(void);
//
// UDPsocket
//
#if defined(I_NET_ENABLED)
SOCKET UDPsocket(void)
{
SOCKET s;
// allocate a socket
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0)
{
//I_Error("Error: can't create socket: %s", strerror(errno));
doom_strcpy(error_buf, "Error: can't create socket: ");
doom_concat(error_buf, strerror(errno));
I_Error(error_buf);
}
return s;
}
#endif
//
// BindToLocalPort
//
#if defined(I_NET_ENABLED)
void BindToLocalPort(SOCKET s, int port)
{
int v;
struct sockaddr_in address;
doom_memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = port;
v = bind(s, (void*)&address, sizeof(address));
if (v == -1)
{
//I_Error("Error: BindToPort: bind: %s", strerror(errno));
doom_strcpy(error_buf, "Error: BindToPort: bind: ");
doom_concat(error_buf, strerror(errno));
I_Error(error_buf);
}
}
#endif
//
// PacketSend
//
void PacketSend(void)
{
#if defined(I_NET_ENABLED)
int c;
doomdata_t sw;
// byte swap
sw.checksum = htonl(netbuffer->checksum);
sw.player = netbuffer->player;
sw.retransmitfrom = netbuffer->retransmitfrom;
sw.starttic = netbuffer->starttic;
sw.numtics = netbuffer->numtics;
for (c = 0; c < netbuffer->numtics; c++)
{
sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
}
//doom_print ("sending %i\n",gametic);
c = sendto(sendsocket, (const char*)&sw, doomcom->datalength
, 0, (void*)&sendaddress[doomcom->remotenode]
, sizeof(sendaddress[doomcom->remotenode]));
#endif
}
//
// PacketGet
//
void PacketGet(void)
{
#if defined(I_NET_ENABLED)
int i;
int c;
struct sockaddr_in fromaddress;
#if defined(__APPLE__)
socklen_t fromlen;
#else
int fromlen;
#endif
doomdata_t sw;
fromlen = sizeof(fromaddress);
c = recvfrom(insocket, (char*)&sw, sizeof(sw), 0
, (struct sockaddr*)&fromaddress, &fromlen);
if (c == -1)
{
#if defined(DOOM_WIN32)
int r = WSAGetLastError();
if (r != WSAEWOULDBLOCK)
{
//I_Error("Error: GetPacket: %i", r);
doom_strcpy(error_buf, "Error: GetPacket: ");
doom_concat(error_buf, doom_itoa(r, 10));
I_Error(error_buf);
}
#else
if (errno != EWOULDBLOCK)
{
//I_Error("Error: GetPacket: %s", strerror(errno));
doom_strcpy(error_buf, "Error: GetPacket: ");
doom_concat(error_buf, strerror(errno));
I_Error(error_buf);
}
#endif
doomcom->remotenode = -1; // no packet
return;
}
{
static int first = 1;
if (first)
{
//doom_print("len=%d:p=[0x%x 0x%x] \n", c, *(int*)&sw, *((int*)&sw + 1));
doom_print("len=");
doom_print(doom_itoa(c, 10));
doom_print(":p=[0x");
doom_print(doom_itoa(*(int*)&sw, 16));
doom_print(" 0x");
doom_print(doom_itoa(*((int*)&sw + 1), 16));
doom_print("] \n");
}
first = 0;
}
// find remote node number
for (i = 0; i < doomcom->numnodes; i++)
if (fromaddress.sin_addr.s_addr == sendaddress[i].sin_addr.s_addr)
break;
if (i == doomcom->numnodes)
{
// packet is not from one of the players (new game broadcast)
doomcom->remotenode = -1; // no packet
return;
}
doomcom->remotenode = i; // good packet from a game player
doomcom->datalength = c;
// byte swap
netbuffer->checksum = ntohl(sw.checksum);
netbuffer->player = sw.player;
netbuffer->retransmitfrom = sw.retransmitfrom;
netbuffer->starttic = sw.starttic;
netbuffer->numtics = sw.numtics;
for (c = 0; c < netbuffer->numtics; c++)
{
netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
netbuffer->cmds[c].chatchar = sw.cmds[c].chatchar;
netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
}
#endif
}
int GetLocalAddress(void)
{
#if defined(I_NET_ENABLED)
char hostname[1024];
struct hostent* hostentry; // host information entry
int v;
// get local address
v = gethostname(hostname, sizeof(hostname));
if (v == -1)
{
//I_Error("Error: GetLocalAddress : gethostname: errno %d", errno);
doom_strcpy(error_buf, "Error: GetLocalAddress : gethostname: errno ");
doom_concat(error_buf, strerror(errno));
I_Error(error_buf);
}
hostentry = gethostbyname(hostname);
if (!hostentry)
{
I_Error("Error: GetLocalAddress : gethostbyname: couldn't get local host");
}
return *(int*)hostentry->h_addr_list[0];
#else
return 0;
#endif
}
//
// I_InitNetwork
//
void I_InitNetwork(void)
{
#if defined(I_NET_ENABLED)
#if defined(DOOM_WIN32)
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
u_long trueval = 1;
#else
doom_boolean trueval = true;
#endif
#endif
int i;
int p;
struct hostent* hostentry; // host information entry
doomcom = doom_malloc(sizeof(*doomcom));
doom_memset(doomcom, 0, sizeof(*doomcom));
// set up for network
i = M_CheckParm("-dup");
if (i && i < myargc - 1)
{
doomcom->ticdup = myargv[i + 1][0] - '0';
if (doomcom->ticdup < 1)
doomcom->ticdup = 1;
if (doomcom->ticdup > 9)
doomcom->ticdup = 9;
}
else
doomcom->ticdup = 1;
if (M_CheckParm("-extratic"))
doomcom->extratics = 1;
else
doomcom->extratics = 0;
p = M_CheckParm("-port");
if (p && p < myargc - 1)
{
DOOMPORT = doom_atoi(myargv[p + 1]);
//doom_print("using alternate port %i\n", DOOMPORT);
doom_print("using alternate port ");
doom_print(doom_itoa(DOOMPORT, 10));
doom_print("\n");
}
p = M_CheckParm("-sendport");
if (p && p < myargc - 1)
{
DOOMPORT_SEND = doom_atoi(myargv[p + 1]);
//doom_print("using alternate send port %i\n", DOOMPORT_SEND);
doom_print("using alternate send port ");
doom_print(doom_itoa(DOOMPORT_SEND, 10));
doom_print("\n");
}
// parse network game options,
// -net <consoleplayer> <host> <host> ...
i = M_CheckParm("-net");
if (!i)
{
// single player game
netgame = false;
doomcom->id = DOOMCOM_ID;
doomcom->numplayers = doomcom->numnodes = 1;
doomcom->deathmatch = false;
doomcom->consoleplayer = 0;
return;
}
#if defined(I_NET_ENABLED)
netsend = PacketSend;
netget = PacketGet;
netgame = true;
// parse player number and host list
doomcom->consoleplayer = myargv[i + 1][0] - '1';
doomcom->numnodes = 1; // this node for sure
i++;
while (++i < myargc && myargv[i][0] != '-')
{
sendaddress[doomcom->numnodes].sin_family = AF_INET;
sendaddress[doomcom->numnodes].sin_port = htons(DOOMPORT);
if (myargv[i][0] == '.')
{
sendaddress[doomcom->numnodes].sin_addr.s_addr
= inet_addr(myargv[i] + 1);
}
else
{
hostentry = gethostbyname(myargv[i]);
if (!hostentry)
{
//I_Error("Error: gethostbyname: couldn't find %s", myargv[i]);
doom_strcpy(error_buf, "Error: gethostbyname: couldn't find ");
doom_concat(error_buf, myargv[i]);
I_Error(error_buf);
}
sendaddress[doomcom->numnodes].sin_addr.s_addr
= *(int*)hostentry->h_addr_list[0];
}
doomcom->numnodes++;
}
doomcom->id = DOOMCOM_ID;
doomcom->numplayers = doomcom->numnodes;
// build message to receive
insocket = UDPsocket();
BindToLocalPort(insocket, htons(DOOMPORT));
#if defined(DOOM_WIN32)
ioctlsocket(insocket, FIONBIO, &trueval);
#else
ioctl(insocket, FIONBIO, &trueval);
#endif
sendsocket = UDPsocket();
#endif
}
void I_NetCmd(void)
{
#if defined(I_NET_ENABLED)
if (doomcom->command == CMD_SEND)
{
netsend();
}
else if (doomcom->command == CMD_GET)
{
netget();
}
else
{
//I_Error("Error: Bad net cmd: %i\n", doomcom->command);
doom_strcpy(error_buf, "Error: Bad net cmd: ");
doom_concat(error_buf, doom_itoa(doomcom->command, 10));
I_Error(error_buf);
}
#endif
}

38
src/DOOM/i_net.h Normal file
View File

@ -0,0 +1,38 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific network interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __I_NET__
#define __I_NET__
// Called by D_DoomMain.
void I_InitNetwork (void);
void I_NetCmd (void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

1168
src/DOOM/i_sound.c Normal file

File diff suppressed because it is too large Load Diff

110
src/DOOM/i_sound.h Normal file
View File

@ -0,0 +1,110 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//
// DESCRIPTION:
// System interface, sound.
//
//-----------------------------------------------------------------------------
#ifndef __I_SOUND__
#define __I_SOUND__
#include "doomdef.h"
#include "doomstat.h"
#include "sounds.h"
// Init at program start...
void I_InitSound();
// ... update sound buffer and audio device at runtime...
void I_UpdateSound(void);
void I_SubmitSound(void);
// ... shut down and relase at program termination.
void I_ShutdownSound(void);
//
// SFX I/O
//
// Initialize channels?
void I_SetChannels();
// Get raw data lump index for sound descriptor.
int I_GetSfxLumpNum(sfxinfo_t* sfxinfo);
// Starts a sound in a particular sound channel.
int I_StartSound(int id, int vol, int sep, int pitch, int priority);
// Stops a sound channel.
void I_StopSound(int handle);
// Called by S_*() functions
// to see if a channel is still playing.
// Returns 0 if no longer playing, 1 if playing.
int I_SoundIsPlaying(int handle);
// Updates the volume, separation,
// and pitch of a sound channel.
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
//
// MUSIC I/O
//
void I_InitMusic(void);
void I_ShutdownMusic(void);
// Volume.
void I_SetMusicVolume(int volume);
// PAUSE game handling.
void I_PauseSong(int handle);
void I_ResumeSong(int handle);
// Registers a song handle to song data.
int I_RegisterSong(void* data);
// Called by anything that wishes to start music.
// plays a song, and when the song is done,
// starts playing it again in an endless loop.
// Horrible thing to do, considering.
void I_PlaySong(int handle, int looping);
// Stops a song over 3 seconds.
void I_StopSong(int handle);
// See above (register), then think backwards
void I_UnRegisterSong(int handle);
// Get next MIDI message
unsigned long I_TickSong();
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

160
src/DOOM/i_system.c Normal file
View File

@ -0,0 +1,160 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "m_misc.h"
#include "i_video.h"
#include "i_sound.h"
#include "d_net.h"
#include "g_game.h"
#include "i_system.h"
int mb_used = 6 * (sizeof(void*) / 4);
ticcmd_t emptycmd;
extern doom_boolean demorecording;
void I_Tactile(int on, int off, int total)
{
}
ticcmd_t* I_BaseTiccmd(void)
{
return &emptycmd;
}
int I_GetHeapSize(void)
{
return mb_used * 1024 * 1024;
}
byte* I_ZoneBase(int* size)
{
*size = mb_used * 1024 * 1024;
return (byte*)doom_malloc(*size);
}
//
// I_GetTime
// returns time in 1/70th second tics
//
int I_GetTime(void)
{
int sec, usec;
int newtics;
static int basetime = 0;
doom_gettime(&sec, &usec);
if (!basetime)
basetime = sec;
newtics = (sec - basetime) * TICRATE + usec * TICRATE / 1000000;
return newtics;
}
//
// I_Init
//
void I_Init(void)
{
I_InitSound();
}
//
// I_Quit
//
void I_Quit(void)
{
D_QuitNetGame();
I_ShutdownSound();
I_ShutdownMusic();
M_SaveDefaults();
I_ShutdownGraphics();
doom_exit(0);
}
void I_WaitVBL(int count)
{
#if 0 // [pd] Never sleep in main thread
#ifdef SGI
sginap(1);
#else
#ifdef SUN
sleep(0);
#else
usleep(count * (1000000 / 70));
#endif
#endif
#endif
}
void I_BeginRead(void)
{
}
void I_EndRead(void)
{
}
byte* I_AllocLow(int length)
{
byte* mem;
mem = (byte*)doom_malloc(length);
doom_memset(mem, 0, length);
return mem;
}
//
// I_Error
//
void I_Error(char* error)
{
// Message first.
if (error) doom_print(error);
doom_print("\n");
// Shutdown. Here might be other errors.
if (demorecording)
G_CheckDemoStatus();
D_QuitNetGame();
I_ShutdownGraphics();
doom_exit(-1);
}

85
src/DOOM/i_system.h Normal file
View File

@ -0,0 +1,85 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __I_SYSTEM__
#define __I_SYSTEM__
#include "d_ticcmd.h"
#include "d_event.h"
// Called by DoomMain.
void I_Init(void);
// Called by startup code
// to get the ammount of memory to malloc
// for the zone management.
byte* I_ZoneBase(int* size);
// Called by D_DoomLoop,
// returns current time in tics.
int I_GetTime(void);
// Called by D_DoomLoop,
// called before processing any tics in a frame
// (just after displaying a frame).
// Time consuming syncronous operations
// are performed here (joystick reading).
// Can call D_PostEvent.
void I_StartFrame(void);
// Called by D_DoomLoop,
// called before processing each tic in a frame.
// Quick syncronous operations are performed here.
// Can call D_PostEvent.
void I_StartTic(void);
// Asynchronous interrupt functions should maintain private queues
// that are read by the synchronous functions
// to be converted into events.
// Either returns a null ticcmd,
// or calls a loadable driver to build it.
// This ticcmd will then be modified by the gameloop
// for normal input.
ticcmd_t* I_BaseTiccmd(void);
// Called by M_Responder when quit is selected.
// Clean exit, displays sell blurb.
void I_Quit(void);
// Allocates from low memory under dos,
// just mallocs under unix
byte* I_AllocLow(int length);
void I_Tactile(int on, int off, int total);
void I_Error(char* error);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

143
src/DOOM/i_video.c Normal file
View File

@ -0,0 +1,143 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// DOOM graphics stuff for X11, UNIX.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomstat.h"
#include "i_system.h"
#include "v_video.h"
#include "m_argv.h"
#include "d_main.h"
#include "doomdef.h"
#define POINTER_WARP_COUNTDOWN 1
// Fake mouse handling.
// This cannot work properly w/o DGA.
// Needs an invisible mouse cursor at least.
doom_boolean grabMouse;
int doPointerWarp = POINTER_WARP_COUNTDOWN;
unsigned char screen_palette[256 * 3];
doom_boolean mousemoved = false;
doom_boolean shmFinished;
// Blocky mode,
// replace each 320x200 pixel with multiply*multiply pixels.
// According to Dave Taylor, it still is a bonehead thing
// to use ....
static int multiply = 1;
static int lastmousex = 0;
static int lastmousey = 0;
void I_ShutdownGraphics(void)
{
}
//
// I_StartFrame
//
void I_StartFrame(void)
{
}
void I_GetEvent(void)
{
}
//
// I_StartTic
//
void I_StartTic(void)
{
}
//
// I_UpdateNoBlit
//
void I_UpdateNoBlit(void)
{
// what is this?
}
//
// I_FinishUpdate
//
void I_FinishUpdate(void)
{
static int lasttic;
int tics;
int i;
// draws little dots on the bottom of the screen
if (devparm)
{
i = I_GetTime();
tics = i - lasttic;
lasttic = i;
if (tics > 20) tics = 20;
for (i = 0; i < tics * 2; i += 2)
screens[0][(SCREENHEIGHT - 1) * SCREENWIDTH + i] = 0xff;
for (; i < 20 * 2; i += 2)
screens[0][(SCREENHEIGHT - 1) * SCREENWIDTH + i] = 0x0;
}
}
//
// I_ReadScreen
//
void I_ReadScreen(byte* scr)
{
doom_memcpy(scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
}
//
// I_SetPalette
//
void I_SetPalette(byte* palette)
{
doom_memcpy(screen_palette, palette, 256 * 3);
}
void I_InitGraphics(void)
{
screens[0] = (unsigned char*)doom_malloc(SCREENWIDTH * SCREENHEIGHT);
}

57
src/DOOM/i_video.h Normal file
View File

@ -0,0 +1,57 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
//-----------------------------------------------------------------------------
#ifndef __I_VIDEO__
#define __I_VIDEO__
#include "doomtype.h"
// Called by D_DoomMain,
// determines the hardware configuration
// and sets up the video mode
void I_InitGraphics(void);
void I_ShutdownGraphics(void);
// Takes full 8 bit values.
void I_SetPalette(byte* palette);
void I_UpdateNoBlit(void);
void I_FinishUpdate(void);
// Wait for vertical retrace or pause a bit.
void I_WaitVBL(int count);
void I_ReadScreen(byte* scr);
void I_BeginRead(void);
void I_EndRead(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

4663
src/DOOM/info.c Normal file

File diff suppressed because it is too large Load Diff

1344
src/DOOM/info.h Normal file

File diff suppressed because it is too large Load Diff

53
src/DOOM/m_argv.c Normal file
View File

@ -0,0 +1,53 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
// #if defined(DOOM_WIN32)
// #define strcasecmp stricmp
// #endif
int myargc;
char** myargv;
//
// M_CheckParm
// Checks for the given parameter
// in the program's command line arguments.
// Returns the argument number (1 to argc-1)
// or 0 if not present
int M_CheckParm(char* check)
{
int i;
for (i = 1; i < myargc; i++)
{
if (!doom_strcasecmp(check, myargv[i]))
return i;
}
return 0;
}

43
src/DOOM/m_argv.h Normal file
View File

@ -0,0 +1,43 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Nil.
//
//-----------------------------------------------------------------------------
#ifndef __M_ARGV__
#define __M_ARGV__
//
// MISC
//
extern int myargc;
extern char** myargv;
// Returns the position of the given parameter
// in the arg list (0 if not found).
int M_CheckParm(char* check);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

50
src/DOOM/m_bbox.c Normal file
View File

@ -0,0 +1,50 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Main loop menu stuff.
// Random number LUT.
// Default Config File.
// PCX Screenshots.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "m_bbox.h"
void M_ClearBox(fixed_t* box)
{
box[BOXTOP] = box[BOXRIGHT] = DOOM_MININT;
box[BOXBOTTOM] = box[BOXLEFT] = DOOM_MAXINT;
}
void M_AddToBox(fixed_t* box, fixed_t x, fixed_t y)
{
if (x < box[BOXLEFT])
box[BOXLEFT] = x;
else if (x > box[BOXRIGHT])
box[BOXRIGHT] = x;
if (y < box[BOXBOTTOM])
box[BOXBOTTOM] = y;
else if (y > box[BOXTOP])
box[BOXTOP] = y;
}

51
src/DOOM/m_bbox.h Normal file
View File

@ -0,0 +1,51 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Nil.
//
//-----------------------------------------------------------------------------
#ifndef __M_BBOX__
#define __M_BBOX__
#include "doomtype.h"
#include "m_fixed.h"
// Bounding box coordinate storage.
enum
{
BOXTOP,
BOXBOTTOM,
BOXLEFT,
BOXRIGHT
}; // bbox coordinates
// Bounding box functions.
void M_ClearBox(fixed_t* box);
void M_AddToBox(fixed_t* box, fixed_t x, fixed_t y);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

91
src/DOOM/m_cheat.c Normal file
View File

@ -0,0 +1,91 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Cheat sequence checking.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "m_cheat.h"
//
// CHEAT SEQUENCE PACKAGE
//
static int firsttime = 1;
static unsigned char cheat_xlate_table[256];
//
// Called in st_stuff module, which handles the input.
// Returns a 1 if the cheat was successful, 0 if failed.
//
int cht_CheckCheat(cheatseq_t* cht, char key)
{
int i;
int rc = 0;
if (firsttime)
{
firsttime = 0;
for (i = 0; i < 256; i++) cheat_xlate_table[i] = SCRAMBLE(i);
}
if (!cht->p)
cht->p = cht->sequence; // initialize if first time
if (*cht->p == 0)
*(cht->p++) = key;
else if
(cheat_xlate_table[(unsigned char)key] == *cht->p) cht->p++;
else
cht->p = cht->sequence;
if (*cht->p == 1)
cht->p++;
else if (*cht->p == 0xff) // end of sequence character
{
cht->p = cht->sequence;
rc = 1;
}
return rc;
}
void cht_GetParam(cheatseq_t* cht, char* buffer)
{
unsigned char* p, c;
p = cht->sequence;
while (*(p++) != 1);
do
{
c = *p;
*(buffer++) = c;
*(p++) = 0;
} while (c && *p != 0xff);
if (*p == 0xff)
*buffer = 0;
}

52
src/DOOM/m_cheat.h Normal file
View File

@ -0,0 +1,52 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Cheat code checking.
//
//-----------------------------------------------------------------------------
#ifndef __M_CHEAT__
#define __M_CHEAT__
//
// CHEAT SEQUENCE PACKAGE
//
#define SCRAMBLE(a) \
((((a)&1)<<7) + (((a)&2)<<5) + ((a)&4) + (((a)&8)<<1) \
+ (((a)&16)>>1) + ((a)&32) + (((a)&64)>>5) + (((a)&128)>>7))
typedef struct
{
unsigned char* sequence;
unsigned char* p;
} cheatseq_t;
int cht_CheckCheat(cheatseq_t* cht, char key);
void cht_GetParam(cheatseq_t* cht, char* buffer);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

59
src/DOOM/m_fixed.c Normal file
View File

@ -0,0 +1,59 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Fixed point implementation.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "stdlib.h"
#include "doomtype.h"
#include "i_system.h"
#include "m_fixed.h"
fixed_t FixedMul(fixed_t a, fixed_t b)
{
return ((long long)a * (long long)b) >> FRACBITS;
}
//
// FixedDiv, C version.
//
fixed_t FixedDiv(fixed_t a, fixed_t b)
{
if ((doom_abs(a) >> 14) >= doom_abs(b))
return (a ^ b) < 0 ? DOOM_MININT : DOOM_MAXINT;
return FixedDiv2(a, b);
}
fixed_t FixedDiv2(fixed_t a, fixed_t b)
{
double c;
c = ((double)a) / ((double)b) * FRACUNIT;
if (c >= 2147483648.0 || c < -2147483648.0)
I_Error("Error: FixedDiv: divide by zero");
return (fixed_t)c;
}

47
src/DOOM/m_fixed.h Normal file
View File

@ -0,0 +1,47 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Fixed point arithemtics, implementation.
//
//-----------------------------------------------------------------------------
#ifndef __M_FIXED__
#define __M_FIXED__
//
// Fixed point, 32bit as 16.16.
//
#define FRACBITS 16
#define FRACUNIT (1<<FRACBITS)
typedef int fixed_t;
fixed_t FixedMul(fixed_t a, fixed_t b);
fixed_t FixedDiv(fixed_t a, fixed_t b);
fixed_t FixedDiv2(fixed_t a, fixed_t b);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

2263
src/DOOM/m_menu.c Normal file

File diff suppressed because it is too large Load Diff

63
src/DOOM/m_menu.h Normal file
View File

@ -0,0 +1,63 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Menu widget stuff, episode selection and such.
//
//-----------------------------------------------------------------------------
#ifndef __M_MENU__
#define __M_MENU__
#include "d_event.h"
//
// MENUS
//
// Called by main loop,
// saves config file and calls I_Quit when user exits.
// Even when the menu is not displayed,
// this can resize the view and change game parameters.
// Does all the real work of the menu interaction.
doom_boolean M_Responder(event_t* ev);
// Called by main loop,
// only used for menu (skull cursor) animation.
void M_Ticker(void);
// Called by main loop,
// draws the menus directly into the screen buffer.
void M_Drawer(void);
// Called by D_DoomMain,
// loads the config file.
void M_Init(void);
// Called by intro code to force menu up upon a keypress,
// does nothing if menu is already up.
void M_StartControlPanel(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

542
src/DOOM/m_misc.c Normal file
View File

@ -0,0 +1,542 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//
// $Log:$
//
// DESCRIPTION:
// Main loop menu stuff.
// Default Config File.
// PCX Screenshots.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "z_zone.h"
#include "m_swap.h"
#include "m_argv.h"
#include "w_wad.h"
#include "i_system.h"
#include "i_video.h"
#include "v_video.h"
#include "hu_stuff.h"
#include "doomstat.h" // State.
#include "dstrings.h" // Data.
#include "m_misc.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define STRING_VALUE 0xFFFF
//
// SCREEN SHOTS
//
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin;
unsigned short ymin;
unsigned short xmax;
unsigned short ymax;
unsigned short hres;
unsigned short vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
//
// M_DrawText
// Returns the final X coordinate
// HU_Init must have been called to init the font
//
extern patch_t* hu_font[HU_FONTSIZE];
//
// DEFAULTS
//
extern int key_right;
extern int key_left;
extern int key_up;
extern int key_down;
extern int key_strafeleft;
extern int key_straferight;
extern int key_fire;
extern int key_use;
extern int key_strafe;
extern int key_speed;
extern int mousebfire;
extern int mousebstrafe;
extern int mousebforward;
extern int mousemove;
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
extern int joybspeed;
extern int viewwidth;
extern int viewheight;
extern int mouseSensitivity;
extern int showMessages;
extern int detailLevel;
extern int screenblocks;
extern int showMessages;
// machine-independent sound params
extern int numChannels;
extern char* chat_macros[];
extern byte scantokey[128];
int usemouse;
int usejoystick;
int crosshair;
int always_run;
default_t defaults[] =
{
{"mouse_sensitivity",&mouseSensitivity, 5},
{"sfx_volume",&snd_SfxVolume, 8},
{"music_volume",&snd_MusicVolume, 8},
{"show_messages",&showMessages, 1},
{"key_right",&key_right, KEY_RIGHTARROW},
{"key_left",&key_left, KEY_LEFTARROW},
{"key_up",&key_up, KEY_UPARROW},
{"key_down",&key_down, KEY_DOWNARROW},
{"key_strafeleft",&key_strafeleft, ','},
{"key_straferight",&key_straferight, '.'},
{"key_fire",&key_fire, KEY_RCTRL},
{"key_use",&key_use, ' '},
{"key_strafe",&key_strafe, KEY_RALT},
{"key_speed",&key_speed, KEY_RSHIFT},
{"use_mouse",&usemouse, 1},
{"mouseb_fire",&mousebfire,0},
{"mouseb_strafe",&mousebstrafe,1},
{"mouseb_forward",&mousebforward,2},
{"mouse_move",&mousemove,0},
{"use_joystick",&usejoystick, 0},
{"joyb_fire",&joybfire,0},
{"joyb_strafe",&joybstrafe,1},
{"joyb_use",&joybuse,3},
{"joyb_speed",&joybspeed,2},
{"screenblocks",&screenblocks, 9},
{"detaillevel",&detailLevel, 0},
{"crosshair",&crosshair, 0},
{"always_run",&always_run, 0},
{"snd_channels",&numChannels, 3},
{"usegamma",&usegamma, 0},
{"chatmacro0", 0, STRING_VALUE, 0, 0, &chat_macros[0], HUSTR_CHATMACRO0 },
{"chatmacro1", 0, STRING_VALUE, 0, 0, &chat_macros[1], HUSTR_CHATMACRO1 },
{"chatmacro2", 0, STRING_VALUE, 0, 0, &chat_macros[2], HUSTR_CHATMACRO2 },
{"chatmacro3", 0, STRING_VALUE, 0, 0, &chat_macros[3], HUSTR_CHATMACRO3 },
{"chatmacro4", 0, STRING_VALUE, 0, 0, &chat_macros[4], HUSTR_CHATMACRO4 },
{"chatmacro5", 0, STRING_VALUE, 0, 0, &chat_macros[5], HUSTR_CHATMACRO5 },
{"chatmacro6", 0, STRING_VALUE, 0, 0, &chat_macros[6], HUSTR_CHATMACRO6 },
{"chatmacro7", 0, STRING_VALUE, 0, 0, &chat_macros[7], HUSTR_CHATMACRO7 },
{"chatmacro8", 0, STRING_VALUE, 0, 0, &chat_macros[8], HUSTR_CHATMACRO8 },
{"chatmacro9", 0, STRING_VALUE, 0, 0, &chat_macros[9], HUSTR_CHATMACRO9 }
};
int numdefaults = sizeof(defaults) / sizeof(default_t);;
char* defaultfile;
int M_DrawText(int x, int y, doom_boolean direct, char* string)
{
int c;
int w;
while (*string)
{
c = doom_toupper(*string) - HU_FONTSTART;
string++;
if (c < 0 || c> HU_FONTSIZE)
{
x += 4;
continue;
}
w = SHORT(hu_font[c]->width);
if (x + w > SCREENWIDTH)
break;
if (direct)
V_DrawPatchDirect(x, y, 0, hu_font[c]);
else
V_DrawPatch(x, y, 0, hu_font[c]);
x += w;
}
return x;
}
//
// M_WriteFile
//
doom_boolean M_WriteFile(char const* name, void* source, int length)
{
void* handle;
int count;
handle = doom_open(name, "wb");
if (handle == 0)
return false;
count = doom_write(handle, source, length);
doom_close(handle);
if (count < length)
return false;
return true;
}
//
// M_ReadFile
//
int M_ReadFile(char const* name, byte** buffer)
{
void* handle;
int count, length;
byte* buf;
handle = doom_open(name, "rb");
if (handle == 0)
{
//I_Error("Error: Couldn't read file %s", name);
doom_strcpy(error_buf, "Error: Couldn't read file ");
doom_concat(error_buf, name);
I_Error(error_buf);
}
doom_seek(handle, 0, DOOM_SEEK_END);
length = doom_tell(handle);
doom_seek(handle, 0, DOOM_SEEK_SET);
buf = Z_Malloc(length, PU_STATIC, 0);
count = doom_read(handle, buf, length);
doom_close(handle);
if (count < length)
{
//I_Error("Error: Couldn't read file %s", name);
doom_strcpy(error_buf, "Error: Couldn't read file ");
doom_concat(error_buf, name);
I_Error(error_buf);
}
*buffer = buf;
return length;
}
//
// M_SaveDefaults
//
void M_SaveDefaults(void)
{
int i;
int v;
void* f;
f = doom_open(defaultfile, "w");
if (!f)
return; // can't write the file, but don't complain
for (i = 0; i < numdefaults; i++)
{
if (defaults[i].defaultvalue > -0xfff
&& defaults[i].defaultvalue < 0xfff)
{
v = *defaults[i].location;
//fprintf(f, "%s\t\t%i\n", defaults[i].name, v);
doom_fprint(f, defaults[i].name);
doom_fprint(f, "\t\t");
doom_fprint(f, doom_itoa(v, 10));
doom_fprint(f, "\n");
}
else
{
//fprintf(f, "%s\t\t\"%s\"\n", defaults[i].name,
// *(char**)(defaults[i].text_location));
doom_fprint(f, defaults[i].name);
doom_fprint(f, "\t\t\"");
doom_fprint(f, *(char**)(defaults[i].text_location));
doom_fprint(f, "\"\n");
}
}
doom_close(f);
}
//
// M_LoadDefaults
//
void M_LoadDefaults(void)
{
int i;
int len;
void* f;
char def[80];
char strparm[100];
char* newstring;
int parm;
doom_boolean isstring;
// set everything to base values
// numdefaults = sizeof(defaults)/sizeof(defaults[0]);
for (i = 0; i < numdefaults; i++)
{
if (defaults[i].defaultvalue == 0xFFFF)
*defaults[i].text_location = defaults[i].default_text_value;
else
*defaults[i].location = (int)defaults[i].defaultvalue;
}
// check for a custom default file
i = M_CheckParm("-config");
if (i && i < myargc - 1)
{
defaultfile = myargv[i + 1];
//doom_print(" default file: %s\n", defaultfile);
doom_print(" default file: ");
doom_print(defaultfile);
doom_print("\n");
}
else
defaultfile = basedefault;
// read the file in, overriding any set defaults
f = doom_open(defaultfile, "r");
if (f)
{
while (!doom_eof(f))
{
// def
int arg_read = 0;
char c;
for (i = 0; i < 79; ++i)
{
doom_read(f, &c, 1);
if (c == ' ' || c == '\n' || c == '\t')
{
if (i > 0) arg_read++;
break;
}
def[i] = c;
}
def[i] = '\0';
// Ignore spaces
if (c != '\n')
{
while (1)
{
doom_read(f, &c, 1);
if (c != ' ' && c != '\t') break;
}
// strparam
i = 0;
if (c != '\n')
{
for (; i < 260;)
{
strparm[i++] = c;
doom_read(f, &c, 1);
if (c == '\n')
{
if (i > 0) arg_read++;
break;
}
}
}
strparm[i] = '\0';
}
isstring = false;
//if (fscanf(f, "%79s %[^\n]\n", def, strparm) == 2)
if (arg_read == 2)
{
if (strparm[0] == '"')
{
// get a string default
isstring = true;
len = (int)doom_strlen(strparm);
newstring = (char*)doom_malloc(len);
strparm[len - 1] = 0;
doom_strcpy(newstring, strparm + 1);
}
else if (strparm[0] == '0' && strparm[1] == 'x')
{
//sscanf(strparm + 2, "%x", &parm);
parm = doom_atox(strparm + 2);
}
else
{
//sscanf(strparm, "%i", &parm);
parm = doom_atoi(strparm);
}
for (i = 0; i < numdefaults; i++)
if (!doom_strcmp(def, defaults[i].name))
{
if (!isstring)
*defaults[i].location = parm;
else
*defaults[i].text_location = newstring;
break;
}
}
}
doom_close(f);
}
}
//
// WritePCXfile
//
void WritePCXfile(char* filename, byte* data, int width, int height, byte* palette)
{
int i;
int length;
pcx_t* pcx;
byte* pack;
pcx = Z_Malloc(width * height * 2 + 1000, PU_STATIC, 0);
pcx->manufacturer = 0x0a; // PCX id
pcx->version = 5; // 256 color
pcx->encoding = 1; // uncompressed
pcx->bits_per_pixel = 8; // 256 color
pcx->xmin = 0;
pcx->ymin = 0;
pcx->xmax = SHORT(width - 1);
pcx->ymax = SHORT(height - 1);
pcx->hres = SHORT(width);
pcx->vres = SHORT(height);
doom_memset(pcx->palette, 0, sizeof(pcx->palette));
pcx->color_planes = 1; // chunky image
pcx->bytes_per_line = SHORT(width);
pcx->palette_type = SHORT(2); // not a grey scale
doom_memset(pcx->filler, 0, sizeof(pcx->filler));
// pack the image
pack = &pcx->data;
for (i = 0; i < width * height; i++)
{
if ((*data & 0xc0) != 0xc0)
*pack++ = *data++;
else
{
*pack++ = 0xc1;
*pack++ = *data++;
}
}
// write the palette
*pack++ = 0x0c; // palette ID byte
for (i = 0; i < 768; i++)
*pack++ = *palette++;
// write output file
length = (int)(pack - (byte*)pcx);
M_WriteFile(filename, pcx, length);
Z_Free(pcx);
}
//
// M_ScreenShot
//
void M_ScreenShot(void)
{
int i;
byte* linear;
char lbmname[12];
void* f;
// munge planar buffer to linear
linear = screens[2];
I_ReadScreen(linear);
// find a file name to save it to
doom_strcpy(lbmname, "DOOM00.pcx");
for (i = 0; i <= 99; i++)
{
lbmname[4] = i / 10 + '0';
lbmname[5] = i % 10 + '0';
if ((f = doom_open(lbmname, "wb")) == 0)
break; // file doesn't exist
doom_close(f);
}
if (i == 100)
I_Error("Error: M_ScreenShot: Couldn't create a PCX");
// save the pcx file
WritePCXfile(lbmname, linear,
SCREENWIDTH, SCREENHEIGHT,
W_CacheLumpName("PLAYPAL", PU_CACHE));
players[consoleplayer].message = "screen shot";
}

58
src/DOOM/m_misc.h Normal file
View File

@ -0,0 +1,58 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __M_MISC__
#define __M_MISC__
#include "doomtype.h"
//
// MISC
//
typedef struct
{
char* name;
int* location;
int defaultvalue;
int scantranslate; // PC scan code hack
int untranslated; // lousy hack
char** text_location; // [pd] int* location was used to store text pointer. Can't change to intptr_t unless we change all settings type
char* default_text_value; // [pd] So we don't change defaultvalue behavior for int to intptr_t
} default_t;
doom_boolean M_WriteFile(char const* name, void* source, int length);
int M_ReadFile(char const* name, byte** buffer);
void M_ScreenShot(void);
void M_LoadDefaults(void);
void M_SaveDefaults(void);
int M_DrawText(int x, int y, doom_boolean direct, char* string);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

77
src/DOOM/m_random.c Normal file
View File

@ -0,0 +1,77 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Random number LUT.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
//
// M_Random
// Returns a 0-255 number
//
unsigned char rndtable[256] = {
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
};
int rndindex = 0;
int prndindex = 0;
// Which one is deterministic?
int P_Random(void)
{
prndindex = (prndindex + 1) & 0xff;
return rndtable[prndindex];
}
int M_Random(void)
{
rndindex = (rndindex + 1) & 0xff;
return rndtable[rndindex];
}
void M_ClearRandom(void)
{
rndindex = prndindex = 0;
}

46
src/DOOM/m_random.h Normal file
View File

@ -0,0 +1,46 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __M_RANDOM__
#define __M_RANDOM__
#include "doomtype.h"
// Returns a number from 0 to 255,
// from a lookup table.
int M_Random(void);
// As M_Random, but used only by the play simulation.
int P_Random(void);
// Fix randoms for demos.
void M_ClearRandom(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

53
src/DOOM/m_swap.c Normal file
View File

@ -0,0 +1,53 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Endianess handling, swapping 16bit and 32bit.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "m_swap.h"
// Not needed with big endian.
#ifdef __BIG_ENDIAN__
// Swap 16bit, that is, MSB and LSB byte.
unsigned short SwapSHORT(unsigned short x)
{
// No masking with 0xFF should be necessary.
return (x >> 8) | (x << 8);
}
// Swapping 32bit.
unsigned long SwapLONG(unsigned long x)
{
return
(x >> 24)
| ((x >> 8) & 0xff00)
| ((x << 8) & 0xff0000)
| (x << 24);
}
#endif

45
src/DOOM/m_swap.h Normal file
View File

@ -0,0 +1,45 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Endianess handling, swapping 16bit and 32bit.
//
//-----------------------------------------------------------------------------
#ifndef __M_SWAP__
#define __M_SWAP__
// Endianess handling.
// WAD files are stored little endian.
#ifdef __BIG_ENDIAN__
unsigned short SwapSHORT(unsigned short);
unsigned long SwapLONG(unsigned long);
#define SHORT(x) ((short)SwapSHORT((unsigned short) (x)))
#define LONG(x) ((long)SwapLONG((unsigned long) (x)))
#else
#define SHORT(x) (x)
#define LONG(x) (x)
#endif
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

322
src/DOOM/p_ceilng.c Normal file
View File

@ -0,0 +1,322 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION: Ceiling aninmation (lowering, crushing, raising)
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
#include "doomstat.h" // State.
#include "r_state.h" // State.
#include "sounds.h" // Data.
//
// CEILINGS
//
ceiling_t* activeceilings[MAXCEILINGS];
//
// T_MoveCeiling
//
void T_MoveCeiling(ceiling_t* ceiling)
{
result_e res;
switch (ceiling->direction)
{
case 0:
// IN STASIS
break;
case 1:
// UP
res = T_MovePlane(ceiling->sector,
ceiling->speed,
ceiling->topheight,
false, 1, ceiling->direction);
if (!(leveltime & 7))
{
switch (ceiling->type)
{
case silentCrushAndRaise:
break;
default:
S_StartSound((mobj_t*)&ceiling->sector->soundorg,
sfx_stnmov);
// ?
break;
}
}
if (res == pastdest)
{
switch (ceiling->type)
{
case raiseToHighest:
P_RemoveActiveCeiling(ceiling);
break;
case silentCrushAndRaise:
S_StartSound((mobj_t*)&ceiling->sector->soundorg,
sfx_pstop);
case fastCrushAndRaise:
case crushAndRaise:
ceiling->direction = -1;
break;
default:
break;
}
}
break;
case -1:
// DOWN
res = T_MovePlane(ceiling->sector,
ceiling->speed,
ceiling->bottomheight,
ceiling->crush, 1, ceiling->direction);
if (!(leveltime & 7))
{
switch (ceiling->type)
{
case silentCrushAndRaise: break;
default:
S_StartSound((mobj_t*)&ceiling->sector->soundorg,
sfx_stnmov);
}
}
if (res == pastdest)
{
switch (ceiling->type)
{
case silentCrushAndRaise:
S_StartSound((mobj_t*)&ceiling->sector->soundorg,
sfx_pstop);
case crushAndRaise:
ceiling->speed = CEILSPEED;
case fastCrushAndRaise:
ceiling->direction = 1;
break;
case lowerAndCrush:
case lowerToFloor:
P_RemoveActiveCeiling(ceiling);
break;
default:
break;
}
}
else // ( res != pastdest )
{
if (res == crushed)
{
switch (ceiling->type)
{
case silentCrushAndRaise:
case crushAndRaise:
case lowerAndCrush:
ceiling->speed = CEILSPEED / 8;
break;
default:
break;
}
}
}
break;
}
}
//
// EV_DoCeiling
// Move a ceiling up/down and all around!
//
int EV_DoCeiling(line_t* line, ceiling_e type)
{
int secnum;
int rtn;
sector_t* sec;
ceiling_t* ceiling;
secnum = -1;
rtn = 0;
// Reactivate in-stasis ceilings...for certain types.
switch (type)
{
case fastCrushAndRaise:
case silentCrushAndRaise:
case crushAndRaise:
P_ActivateInStasisCeiling(line);
default:
break;
}
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
// new door thinker
rtn = 1;
ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVSPEC, 0);
P_AddThinker(&ceiling->thinker);
sec->specialdata = ceiling;
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
ceiling->sector = sec;
ceiling->crush = false;
switch (type)
{
case fastCrushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
ceiling->bottomheight = sec->floorheight + (8 * FRACUNIT);
ceiling->direction = -1;
ceiling->speed = CEILSPEED * 2;
break;
case silentCrushAndRaise:
case crushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
case lowerAndCrush:
case lowerToFloor:
ceiling->bottomheight = sec->floorheight;
if (type != lowerToFloor)
ceiling->bottomheight += 8 * FRACUNIT;
ceiling->direction = -1;
ceiling->speed = CEILSPEED;
break;
case raiseToHighest:
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
ceiling->direction = 1;
ceiling->speed = CEILSPEED;
break;
}
ceiling->tag = sec->tag;
ceiling->type = type;
P_AddActiveCeiling(ceiling);
}
return rtn;
}
//
// Add an active ceiling
//
void P_AddActiveCeiling(ceiling_t* c)
{
int i;
for (i = 0; i < MAXCEILINGS; i++)
{
if (activeceilings[i] == 0)
{
activeceilings[i] = c;
return;
}
}
}
//
// Remove a ceiling's thinker
//
void P_RemoveActiveCeiling(ceiling_t* c)
{
int i;
for (i = 0; i < MAXCEILINGS; i++)
{
if (activeceilings[i] == c)
{
activeceilings[i]->sector->specialdata = 0;
P_RemoveThinker(&activeceilings[i]->thinker);
activeceilings[i] = 0;
break;
}
}
}
//
// Restart a ceiling that's in-stasis
//
void P_ActivateInStasisCeiling(line_t* line)
{
int i;
for (i = 0; i < MAXCEILINGS; i++)
{
if (activeceilings[i]
&& (activeceilings[i]->tag == line->tag)
&& (activeceilings[i]->direction == 0))
{
activeceilings[i]->direction = activeceilings[i]->olddirection;
activeceilings[i]->thinker.function.acp1
= (actionf_p1)T_MoveCeiling;
}
}
}
//
// EV_CeilingCrushStop
// Stop a ceiling from crushing!
//
int EV_CeilingCrushStop(line_t* line)
{
int i;
int rtn;
rtn = 0;
for (i = 0; i < MAXCEILINGS; i++)
{
if (activeceilings[i]
&& (activeceilings[i]->tag == line->tag)
&& (activeceilings[i]->direction != 0))
{
activeceilings[i]->olddirection = activeceilings[i]->direction;
activeceilings[i]->thinker.function.acv = (actionf_v)0;
activeceilings[i]->direction = 0; // in-stasis
rtn = 1;
}
}
return rtn;
}

517
src/DOOM/p_doors.c Normal file
View File

@ -0,0 +1,517 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION: Door animation code (opening/closing)
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
#include "doomstat.h" // State.
#include "r_state.h" // State.
#include "dstrings.h" // Data.
#include "sounds.h" // Data.
//
// VERTICAL DOORS
//
//
// T_VerticalDoor
//
void T_VerticalDoor(vldoor_t* door)
{
result_e res;
switch (door->direction)
{
case 0:
// WAITING
if (!--door->topcountdown)
{
switch (door->type)
{
case blazeRaise:
door->direction = -1; // time to go back down
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_bdcls);
break;
case door_normal:
door->direction = -1; // time to go back down
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_dorcls);
break;
case close30ThenOpen:
door->direction = 1;
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_doropn);
break;
default:
break;
}
}
break;
case 2:
// INITIAL WAIT
if (!--door->topcountdown)
{
switch (door->type)
{
case raiseIn5Mins:
door->direction = 1;
door->type = door_normal;
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_doropn);
break;
default:
break;
}
}
break;
case -1:
// DOWN
res = T_MovePlane(door->sector,
door->speed,
door->sector->floorheight,
false, 1, door->direction);
if (res == pastdest)
{
switch (door->type)
{
case blazeRaise:
case blazeClose:
door->sector->specialdata = 0;
P_RemoveThinker(&door->thinker); // unlink and free
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_bdcls);
break;
case door_normal:
case door_close:
door->sector->specialdata = 0;
P_RemoveThinker(&door->thinker); // unlink and free
break;
case close30ThenOpen:
door->direction = 0;
door->topcountdown = 35 * 30;
break;
default:
break;
}
}
else if (res == crushed)
{
switch (door->type)
{
case blazeClose:
case door_close: // DO NOT GO BACK UP!
break;
default:
door->direction = 1;
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_doropn);
break;
}
}
break;
case 1:
// UP
res = T_MovePlane(door->sector,
door->speed,
door->topheight,
false, 1, door->direction);
if (res == pastdest)
{
switch (door->type)
{
case blazeRaise:
case door_normal:
door->direction = 0; // wait at top
door->topcountdown = door->topwait;
break;
case close30ThenOpen:
case blazeOpen:
case door_open:
door->sector->specialdata = 0;
P_RemoveThinker(&door->thinker); // unlink and free
break;
default:
break;
}
}
break;
}
}
//
// EV_DoLockedDoor
// Move a locked door up/down
//
int EV_DoLockedDoor(line_t* line, vldoor_e type, mobj_t* thing)
{
player_t* p;
p = thing->player;
if (!p)
return 0;
switch (line->special)
{
case 99: // Blue Lock
case 133:
if (!p)
return 0;
if (!p->cards[it_bluecard] && !p->cards[it_blueskull])
{
p->message = PD_BLUEO;
S_StartSound(0, sfx_oof);
return 0;
}
break;
case 134: // Red Lock
case 135:
if (!p)
return 0;
if (!p->cards[it_redcard] && !p->cards[it_redskull])
{
p->message = PD_REDO;
S_StartSound(0, sfx_oof);
return 0;
}
break;
case 136: // Yellow Lock
case 137:
if (!p)
return 0;
if (!p->cards[it_yellowcard] &&
!p->cards[it_yellowskull])
{
p->message = PD_YELLOWO;
S_StartSound(0, sfx_oof);
return 0;
}
break;
}
return EV_DoDoor(line, type);
}
int EV_DoDoor(line_t* line, vldoor_e type)
{
int secnum, rtn;
sector_t* sec;
vldoor_t* door;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
// new door thinker
rtn = 1;
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
door->sector = sec;
door->type = type;
door->topwait = VDOORWAIT;
door->speed = VDOORSPEED;
switch (type)
{
case blazeClose:
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4 * FRACUNIT;
door->direction = -1;
door->speed = VDOORSPEED * 4;
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_bdcls);
break;
case door_close:
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4 * FRACUNIT;
door->direction = -1;
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_dorcls);
break;
case close30ThenOpen:
door->topheight = sec->ceilingheight;
door->direction = -1;
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_dorcls);
break;
case blazeRaise:
case blazeOpen:
door->direction = 1;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4 * FRACUNIT;
door->speed = VDOORSPEED * 4;
if (door->topheight != sec->ceilingheight)
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_bdopn);
break;
case door_normal:
case door_open:
door->direction = 1;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4 * FRACUNIT;
if (door->topheight != sec->ceilingheight)
S_StartSound((mobj_t*)&door->sector->soundorg,
sfx_doropn);
break;
default:
break;
}
}
return rtn;
}
//
// EV_VerticalDoor : open a door manually, no tag value
//
void EV_VerticalDoor(line_t* line, mobj_t* thing)
{
player_t* player;
int secnum;
sector_t* sec;
vldoor_t* door;
int side;
side = 0; // only front sides can be used
// Check for locks
player = thing->player;
switch (line->special)
{
case 26: // Blue Lock
case 32:
if (!player)
return;
if (!player->cards[it_bluecard] && !player->cards[it_blueskull])
{
player->message = PD_BLUEK;
S_StartSound(0, sfx_oof);
return;
}
break;
case 27: // Yellow Lock
case 34:
if (!player)
return;
if (!player->cards[it_yellowcard] &&
!player->cards[it_yellowskull])
{
player->message = PD_YELLOWK;
S_StartSound(0, sfx_oof);
return;
}
break;
case 28: // Red Lock
case 33:
if (!player)
return;
if (!player->cards[it_redcard] && !player->cards[it_redskull])
{
player->message = PD_REDK;
S_StartSound(0, sfx_oof);
return;
}
break;
}
// if the sector has an active thinker, use it
sec = sides[line->sidenum[side ^ 1]].sector;
secnum = (int)(sec - sectors);
if (sec->specialdata)
{
door = sec->specialdata;
switch (line->special)
{
case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s
case 26:
case 27:
case 28:
case 117:
if (door->direction == -1)
door->direction = 1; // go back up
else
{
if (!thing->player)
return; // JDC: bad guys never close doors
door->direction = -1; // start going down immediately
}
return;
}
}
// for proper sound
switch (line->special)
{
case 117: // BLAZING DOOR RAISE
case 118: // BLAZING DOOR OPEN
S_StartSound((mobj_t*)&sec->soundorg, sfx_bdopn);
break;
case 1: // NORMAL DOOR SOUND
case 31:
S_StartSound((mobj_t*)&sec->soundorg, sfx_doropn);
break;
default: // LOCKED DOOR SOUND
S_StartSound((mobj_t*)&sec->soundorg, sfx_doropn);
break;
}
// new door thinker
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
door->sector = sec;
door->direction = 1;
door->speed = VDOORSPEED;
door->topwait = VDOORWAIT;
switch (line->special)
{
case 1:
case 26:
case 27:
case 28:
door->type = door_normal;
break;
case 31:
case 32:
case 33:
case 34:
door->type = door_open;
line->special = 0;
break;
case 117: // blazing door raise
door->type = blazeRaise;
door->speed = VDOORSPEED * 4;
break;
case 118: // blazing door open
door->type = blazeOpen;
line->special = 0;
door->speed = VDOORSPEED * 4;
break;
}
// find the top and bottom of the movement range
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4 * FRACUNIT;
}
//
// Spawn a door that closes after 30 seconds
//
void P_SpawnDoorCloseIn30(sector_t* sec)
{
vldoor_t* door;
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
sec->special = 0;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
door->sector = sec;
door->direction = 0;
door->type = door_normal;
door->speed = VDOORSPEED;
door->topcountdown = 30 * 35;
}
//
// Spawn a door that opens after 5 minutes
//
void P_SpawnDoorRaiseIn5Mins(sector_t* sec, int secnum)
{
vldoor_t* door;
door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker(&door->thinker);
sec->specialdata = door;
sec->special = 0;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
door->sector = sec;
door->direction = 2;
door->type = raiseIn5Mins;
door->speed = VDOORSPEED;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4 * FRACUNIT;
door->topwait = VDOORWAIT;
door->topcountdown = 5 * 60 * 35;
}

1957
src/DOOM/p_enemy.c Normal file

File diff suppressed because it is too large Load Diff

541
src/DOOM/p_floor.c Normal file
View File

@ -0,0 +1,541 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Floor animation: raising stairs.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
#include "doomstat.h" // State.
#include "r_state.h" // State.
#include "sounds.h" // Data.
//
// FLOORS
//
//
// Move a plane (floor or ceiling) and check for crushing
//
result_e T_MovePlane(sector_t* sector,
fixed_t speed,
fixed_t dest,
doom_boolean crush,
int floorOrCeiling,
int direction)
{
doom_boolean flag;
fixed_t lastpos;
switch (floorOrCeiling)
{
case 0:
// FLOOR
switch (direction)
{
case -1:
// DOWN
if (sector->floorheight - speed < dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector, crush);
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->floorheight;
sector->floorheight -= speed;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector, crush);
return crushed;
}
}
break;
case 1:
// UP
if (sector->floorheight + speed > dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector, crush);
//return crushed;
}
return pastdest;
}
else
{
// COULD GET CRUSHED
lastpos = sector->floorheight;
sector->floorheight += speed;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
if (crush == true)
return crushed;
sector->floorheight = lastpos;
P_ChangeSector(sector, crush);
return crushed;
}
}
break;
}
break;
case 1:
// CEILING
switch (direction)
{
case -1:
// DOWN
if (sector->ceilingheight - speed < dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector, crush);
//return crushed;
}
return pastdest;
}
else
{
// COULD GET CRUSHED
lastpos = sector->ceilingheight;
sector->ceilingheight -= speed;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
if (crush == true)
return crushed;
sector->ceilingheight = lastpos;
P_ChangeSector(sector, crush);
return crushed;
}
}
break;
case 1:
// UP
if (sector->ceilingheight + speed > dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
flag = P_ChangeSector(sector, crush);
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector, crush);
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->ceilingheight;
sector->ceilingheight += speed;
flag = P_ChangeSector(sector, crush);
// UNUSED
#if 0
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector, crush);
return crushed;
}
#endif
}
break;
}
break;
}
return ok;
}
//
// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
//
void T_MoveFloor(floormove_t* floor)
{
result_e res;
res = T_MovePlane(floor->sector,
floor->speed,
floor->floordestheight,
floor->crush, 0, floor->direction);
if (!(leveltime & 7))
S_StartSound((mobj_t*)&floor->sector->soundorg,
sfx_stnmov);
if (res == pastdest)
{
floor->sector->specialdata = 0;
if (floor->direction == 1)
{
switch (floor->type)
{
case donutRaise:
floor->sector->special = floor->newspecial;
floor->sector->floorpic = floor->texture;
default:
break;
}
}
else if (floor->direction == -1)
{
switch (floor->type)
{
case lowerAndChange:
floor->sector->special = floor->newspecial;
floor->sector->floorpic = floor->texture;
default:
break;
}
}
P_RemoveThinker(&floor->thinker);
S_StartSound((mobj_t*)&floor->sector->soundorg,
sfx_pstop);
}
}
//
// HANDLE FLOOR TYPES
//
int EV_DoFloor(line_t* line, floor_e floortype)
{
int secnum;
int rtn;
int i;
sector_t* sec;
floormove_t* floor;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (sec->specialdata)
continue;
// new floor thinker
rtn = 1;
floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker(&floor->thinker);
sec->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
floor->type = floortype;
floor->crush = false;
switch (floortype)
{
case lowerFloor:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindHighestFloorSurrounding(sec);
break;
case lowerFloorToLowest:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestFloorSurrounding(sec);
break;
case turboLower:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED * 4;
floor->floordestheight =
P_FindHighestFloorSurrounding(sec);
if (floor->floordestheight != sec->floorheight)
floor->floordestheight += 8 * FRACUNIT;
break;
case raiseFloorCrush:
floor->crush = true;
case raiseFloor:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestCeilingSurrounding(sec);
if (floor->floordestheight > sec->ceilingheight)
floor->floordestheight = sec->ceilingheight;
floor->floordestheight -= (8 * FRACUNIT) *
(floortype == raiseFloorCrush);
break;
case raiseFloorTurbo:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED * 4;
floor->floordestheight =
P_FindNextHighestFloor(sec, sec->floorheight);
break;
case raiseFloorToNearest:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindNextHighestFloor(sec, sec->floorheight);
break;
case raiseFloor24:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
24 * FRACUNIT;
break;
case raiseFloor512:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
512 * FRACUNIT;
break;
case raiseFloor24AndChange:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
24 * FRACUNIT;
sec->floorpic = line->frontsector->floorpic;
sec->special = line->frontsector->special;
break;
case raiseToTexture:
{
int minsize = DOOM_MAXINT;
side_t* side;
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
for (i = 0; i < sec->linecount; i++)
{
if (twoSided(secnum, i))
{
side = getSide(secnum, i, 0);
if (side->bottomtexture >= 0)
if (textureheight[side->bottomtexture] <
minsize)
minsize =
textureheight[side->bottomtexture];
side = getSide(secnum, i, 1);
if (side->bottomtexture >= 0)
if (textureheight[side->bottomtexture] <
minsize)
minsize =
textureheight[side->bottomtexture];
}
}
floor->floordestheight =
floor->sector->floorheight + minsize;
}
break;
case lowerAndChange:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestFloorSurrounding(sec);
floor->texture = sec->floorpic;
for (i = 0; i < sec->linecount; i++)
{
if (twoSided(secnum, i))
{
if (getSide(secnum, i, 0)->sector - sectors == secnum)
{
sec = getSector(secnum, i, 1);
if (sec->floorheight == floor->floordestheight)
{
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
break;
}
}
else
{
sec = getSector(secnum, i, 0);
if (sec->floorheight == floor->floordestheight)
{
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
break;
}
}
}
}
default:
break;
}
}
return rtn;
}
//
// BUILD A STAIRCASE!
//
int EV_BuildStairs(line_t* line, stair_e type)
{
int secnum;
int height;
int i;
int newsecnum;
int texture;
int ok;
int rtn;
sector_t* sec;
sector_t* tsec;
floormove_t* floor;
fixed_t stairsize;
fixed_t speed;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (sec->specialdata)
continue;
// new floor thinker
rtn = 1;
floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker(&floor->thinker);
sec->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
floor->direction = 1;
floor->sector = sec;
switch (type)
{
case build8:
speed = FLOORSPEED / 4;
stairsize = 8 * FRACUNIT;
break;
case turbo16:
speed = FLOORSPEED * 4;
stairsize = 16 * FRACUNIT;
break;
}
floor->speed = speed;
height = sec->floorheight + stairsize;
floor->floordestheight = height;
texture = sec->floorpic;
// Find next sector to raise
// 1. Find 2-sided line with same sector side[0]
// 2. Other side is the next sector to raise
do
{
ok = 0;
for (i = 0; i < sec->linecount; i++)
{
if (!((sec->lines[i])->flags & ML_TWOSIDED))
continue;
tsec = (sec->lines[i])->frontsector;
newsecnum = (int)(tsec - sectors);
if (secnum != newsecnum)
continue;
tsec = (sec->lines[i])->backsector;
newsecnum = (int)(tsec - sectors);
if (tsec->floorpic != texture)
continue;
height += stairsize;
if (tsec->specialdata)
continue;
sec = tsec;
secnum = newsecnum;
floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker(&floor->thinker);
sec->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
floor->direction = 1;
floor->sector = sec;
floor->speed = speed;
floor->floordestheight = height;
ok = 1;
break;
}
} while (ok);
}
return rtn;
}

924
src/DOOM/p_inter.c Normal file
View File

@ -0,0 +1,924 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Handling interactions (i.e., collisions).
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
// Data.
#include "doomdef.h"
#include "dstrings.h"
#include "sounds.h"
#include "doomstat.h"
#include "m_random.h"
#include "i_system.h"
#include "am_map.h"
#include "p_local.h"
#include "s_sound.h"
#ifdef __GNUG__
#pragma implementation "p_inter.h"
#endif
#include "p_inter.h"
#define BONUSADD 6
// a weapon is found with two clip loads,
// a big item has five clip loads
int maxammo[NUMAMMO] = {200, 50, 300, 50};
int clipammo[NUMAMMO] = {10, 4, 20, 1};
//
// GET STUFF
//
//
// P_GiveAmmo
// Num is the number of clip loads,
// not the individual count (0= 1/2 clip).
// Returns false if the ammo can't be picked up at all
//
doom_boolean
P_GiveAmmo
( player_t* player,
ammotype_t ammo,
int num )
{
int oldammo;
if (ammo == am_noammo)
return false;
if (ammo < 0 || ammo > NUMAMMO)
{
//I_Error ("P_GiveAmmo: bad type %i", ammo);
doom_strcpy(error_buf, "P_GiveAmmo: bad type ");
doom_concat(error_buf, doom_itoa(ammo, 10));
I_Error(error_buf);
}
if ( player->ammo[ammo] == player->maxammo[ammo] )
return false;
if (num)
num *= clipammo[ammo];
else
num = clipammo[ammo]/2;
if (gameskill == sk_baby
|| gameskill == sk_nightmare)
{
// give double ammo in trainer mode,
// you'll need in nightmare
num <<= 1;
}
oldammo = player->ammo[ammo];
player->ammo[ammo] += num;
if (player->ammo[ammo] > player->maxammo[ammo])
player->ammo[ammo] = player->maxammo[ammo];
// If non zero ammo,
// don't change up weapons,
// player was lower on purpose.
if (oldammo)
return true;
// We were down to zero,
// so select a new weapon.
// Preferences are not user selectable.
switch (ammo)
{
case am_clip:
if (player->readyweapon == wp_fist)
{
if (player->weaponowned[wp_chaingun])
player->pendingweapon = wp_chaingun;
else
player->pendingweapon = wp_pistol;
}
break;
case am_shell:
if (player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol)
{
if (player->weaponowned[wp_shotgun])
player->pendingweapon = wp_shotgun;
}
break;
case am_cell:
if (player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol)
{
if (player->weaponowned[wp_plasma])
player->pendingweapon = wp_plasma;
}
break;
case am_misl:
if (player->readyweapon == wp_fist)
{
if (player->weaponowned[wp_missile])
player->pendingweapon = wp_missile;
}
default:
break;
}
return true;
}
//
// P_GiveWeapon
// The weapon name may have a MF_DROPPED flag ored in.
//
doom_boolean
P_GiveWeapon
( player_t* player,
weapontype_t weapon,
doom_boolean dropped )
{
doom_boolean gaveammo;
doom_boolean gaveweapon;
if (netgame
&& (deathmatch!=2)
&& !dropped )
{
// leave placed weapons forever on net games
if (player->weaponowned[weapon])
return false;
player->bonuscount += BONUSADD;
player->weaponowned[weapon] = true;
if (deathmatch)
P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
else
P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
player->pendingweapon = weapon;
if (player == &players[consoleplayer])
S_StartSound (0, sfx_wpnup);
return false;
}
if (weaponinfo[weapon].ammo != am_noammo)
{
// give one clip with a dropped weapon,
// two clips with a found weapon
if (dropped)
gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
else
gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
}
else
gaveammo = false;
if (player->weaponowned[weapon])
gaveweapon = false;
else
{
gaveweapon = true;
player->weaponowned[weapon] = true;
player->pendingweapon = weapon;
}
return (gaveweapon || gaveammo);
}
//
// P_GiveBody
// Returns false if the body isn't needed at all
//
doom_boolean
P_GiveBody
( player_t* player,
int num )
{
if (player->health >= MAXHEALTH)
return false;
player->health += num;
if (player->health > MAXHEALTH)
player->health = MAXHEALTH;
player->mo->health = player->health;
return true;
}
//
// P_GiveArmor
// Returns false if the armor is worse
// than the current armor.
//
doom_boolean
P_GiveArmor
( player_t* player,
int armortype )
{
int hits;
hits = armortype*100;
if (player->armorpoints >= hits)
return false; // don't pick up
player->armortype = armortype;
player->armorpoints = hits;
return true;
}
//
// P_GiveCard
//
void
P_GiveCard
( player_t* player,
card_t card )
{
if (player->cards[card])
return;
player->bonuscount = BONUSADD;
player->cards[card] = 1;
}
//
// P_GivePower
//
doom_boolean
P_GivePower
( player_t* player,
int /*powertype_t*/ power )
{
if (power == pw_invulnerability)
{
player->powers[power] = INVULNTICS;
return true;
}
if (power == pw_invisibility)
{
player->powers[power] = INVISTICS;
player->mo->flags |= MF_SHADOW;
return true;
}
if (power == pw_infrared)
{
player->powers[power] = INFRATICS;
return true;
}
if (power == pw_ironfeet)
{
player->powers[power] = IRONTICS;
return true;
}
if (power == pw_strength)
{
P_GiveBody (player, 100);
player->powers[power] = 1;
return true;
}
if (player->powers[power])
return false; // already got it
player->powers[power] = 1;
return true;
}
//
// P_TouchSpecialThing
//
void
P_TouchSpecialThing
( mobj_t* special,
mobj_t* toucher )
{
player_t* player;
int i;
fixed_t delta;
int sound;
delta = special->z - toucher->z;
if (delta > toucher->height
|| delta < -8*FRACUNIT)
{
// out of reach
return;
}
sound = sfx_itemup;
player = toucher->player;
// Dead thing touching.
// Can happen with a sliding player corpse.
if (toucher->health <= 0)
return;
// Identify by sprite.
switch (special->sprite)
{
// armor
case SPR_ARM1:
if (!P_GiveArmor (player, 1))
return;
player->message = GOTARMOR;
break;
case SPR_ARM2:
if (!P_GiveArmor (player, 2))
return;
player->message = GOTMEGA;
break;
// bonus items
case SPR_BON1:
player->health++; // can go over 100%
if (player->health > 200)
player->health = 200;
player->mo->health = player->health;
player->message = GOTHTHBONUS;
break;
case SPR_BON2:
player->armorpoints++; // can go over 100%
if (player->armorpoints > 200)
player->armorpoints = 200;
if (!player->armortype)
player->armortype = 1;
player->message = GOTARMBONUS;
break;
case SPR_SOUL:
player->health += 100;
if (player->health > 200)
player->health = 200;
player->mo->health = player->health;
player->message = GOTSUPER;
sound = sfx_getpow;
break;
case SPR_MEGA:
if (gamemode != commercial)
return;
player->health = 200;
player->mo->health = player->health;
P_GiveArmor (player,2);
player->message = GOTMSPHERE;
sound = sfx_getpow;
break;
// cards
// leave cards for everyone
case SPR_BKEY:
if (!player->cards[it_bluecard])
player->message = GOTBLUECARD;
P_GiveCard (player, it_bluecard);
if (!netgame)
break;
return;
case SPR_YKEY:
if (!player->cards[it_yellowcard])
player->message = GOTYELWCARD;
P_GiveCard (player, it_yellowcard);
if (!netgame)
break;
return;
case SPR_RKEY:
if (!player->cards[it_redcard])
player->message = GOTREDCARD;
P_GiveCard (player, it_redcard);
if (!netgame)
break;
return;
case SPR_BSKU:
if (!player->cards[it_blueskull])
player->message = GOTBLUESKUL;
P_GiveCard (player, it_blueskull);
if (!netgame)
break;
return;
case SPR_YSKU:
if (!player->cards[it_yellowskull])
player->message = GOTYELWSKUL;
P_GiveCard (player, it_yellowskull);
if (!netgame)
break;
return;
case SPR_RSKU:
if (!player->cards[it_redskull])
player->message = GOTREDSKULL;
P_GiveCard (player, it_redskull);
if (!netgame)
break;
return;
// medikits, heals
case SPR_STIM:
if (!P_GiveBody (player, 10))
return;
player->message = GOTSTIM;
break;
case SPR_MEDI:
if (!P_GiveBody (player, 25))
return;
if (player->health < 25)
player->message = GOTMEDINEED;
else
player->message = GOTMEDIKIT;
break;
// power ups
case SPR_PINV:
if (!P_GivePower (player, pw_invulnerability))
return;
player->message = GOTINVUL;
sound = sfx_getpow;
break;
case SPR_PSTR:
if (!P_GivePower (player, pw_strength))
return;
player->message = GOTBERSERK;
if (player->readyweapon != wp_fist)
player->pendingweapon = wp_fist;
sound = sfx_getpow;
break;
case SPR_PINS:
if (!P_GivePower (player, pw_invisibility))
return;
player->message = GOTINVIS;
sound = sfx_getpow;
break;
case SPR_SUIT:
if (!P_GivePower (player, pw_ironfeet))
return;
player->message = GOTSUIT;
sound = sfx_getpow;
break;
case SPR_PMAP:
if (!P_GivePower (player, pw_allmap))
return;
player->message = GOTMAP;
sound = sfx_getpow;
break;
case SPR_PVIS:
if (!P_GivePower (player, pw_infrared))
return;
player->message = GOTVISOR;
sound = sfx_getpow;
break;
// ammo
case SPR_CLIP:
if (special->flags & MF_DROPPED)
{
if (!P_GiveAmmo (player,am_clip,0))
return;
}
else
{
if (!P_GiveAmmo (player,am_clip,1))
return;
}
player->message = GOTCLIP;
break;
case SPR_AMMO:
if (!P_GiveAmmo (player, am_clip,5))
return;
player->message = GOTCLIPBOX;
break;
case SPR_ROCK:
if (!P_GiveAmmo (player, am_misl,1))
return;
player->message = GOTROCKET;
break;
case SPR_BROK:
if (!P_GiveAmmo (player, am_misl,5))
return;
player->message = GOTROCKBOX;
break;
case SPR_CELL:
if (!P_GiveAmmo (player, am_cell,1))
return;
player->message = GOTCELL;
break;
case SPR_CELP:
if (!P_GiveAmmo (player, am_cell,5))
return;
player->message = GOTCELLBOX;
break;
case SPR_SHEL:
if (!P_GiveAmmo (player, am_shell,1))
return;
player->message = GOTSHELLS;
break;
case SPR_SBOX:
if (!P_GiveAmmo (player, am_shell,5))
return;
player->message = GOTSHELLBOX;
break;
case SPR_BPAK:
if (!player->backpack)
{
for (i=0 ; i<NUMAMMO ; i++)
player->maxammo[i] *= 2;
player->backpack = true;
}
for (i=0 ; i<NUMAMMO ; i++)
P_GiveAmmo (player, i, 1);
player->message = GOTBACKPACK;
break;
// weapons
case SPR_BFUG:
if (!P_GiveWeapon (player, wp_bfg, false) )
return;
player->message = GOTBFG9000;
sound = sfx_wpnup;
break;
case SPR_MGUN:
if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
return;
player->message = GOTCHAINGUN;
sound = sfx_wpnup;
break;
case SPR_CSAW:
if (!P_GiveWeapon (player, wp_chainsaw, false) )
return;
player->message = GOTCHAINSAW;
sound = sfx_wpnup;
break;
case SPR_LAUN:
if (!P_GiveWeapon (player, wp_missile, false) )
return;
player->message = GOTLAUNCHER;
sound = sfx_wpnup;
break;
case SPR_PLAS:
if (!P_GiveWeapon (player, wp_plasma, false) )
return;
player->message = GOTPLASMA;
sound = sfx_wpnup;
break;
case SPR_SHOT:
if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
return;
player->message = GOTSHOTGUN;
sound = sfx_wpnup;
break;
case SPR_SGN2:
if (!P_GiveWeapon (player, wp_supershotgun, special->flags&MF_DROPPED ) )
return;
player->message = GOTSHOTGUN2;
sound = sfx_wpnup;
break;
default:
I_Error ("P_SpecialThing: Unknown gettable thing");
}
if (special->flags & MF_COUNTITEM)
player->itemcount++;
P_RemoveMobj (special);
player->bonuscount += BONUSADD;
if (player == &players[consoleplayer])
S_StartSound (0, sound);
}
//
// KillMobj
//
void
P_KillMobj
( mobj_t* source,
mobj_t* target )
{
mobjtype_t item;
mobj_t* mo;
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
if (target->type != MT_SKULL)
target->flags &= ~MF_NOGRAVITY;
target->flags |= MF_CORPSE|MF_DROPOFF;
target->height >>= 2;
if (source && source->player)
{
// count for intermission
if (target->flags & MF_COUNTKILL)
source->player->killcount++;
if (target->player)
source->player->frags[target->player-players]++;
}
else if (!netgame && (target->flags & MF_COUNTKILL) )
{
// count all monster deaths,
// even those caused by other monsters
players[0].killcount++;
}
if (target->player)
{
// count environment kills against you
if (!source)
target->player->frags[target->player-players]++;
target->flags &= ~MF_SOLID;
target->player->playerstate = PST_DEAD;
P_DropWeapon (target->player);
if (target->player == &players[consoleplayer]
&& automapactive)
{
// don't die in auto map,
// switch view prior to dying
AM_Stop ();
}
}
if (target->health < -target->info->spawnhealth
&& target->info->xdeathstate)
{
P_SetMobjState (target, target->info->xdeathstate);
}
else
P_SetMobjState (target, target->info->deathstate);
target->tics -= P_Random()&3;
if (target->tics < 1)
target->tics = 1;
// I_StartSound (&actor->r, actor->info->deathsound);
// Drop stuff.
// This determines the kind of object spawned
// during the death frame of a thing.
switch (target->type)
{
case MT_WOLFSS:
case MT_POSSESSED:
item = MT_CLIP;
break;
case MT_SHOTGUY:
item = MT_SHOTGUN;
break;
case MT_CHAINGUY:
item = MT_CHAINGUN;
break;
default:
return;
}
mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
mo->flags |= MF_DROPPED; // special versions of items
}
//
// P_DamageMobj
// Damages both enemies and players
// "inflictor" is the thing that caused the damage
// creature or missile, can be 0 (slime, etc)
// "source" is the thing to target after taking damage
// creature or 0
// Source and inflictor are the same for melee attacks.
// Source can be 0 for slime, barrel explosions
// and other environmental stuff.
//
void
P_DamageMobj
( mobj_t* target,
mobj_t* inflictor,
mobj_t* source,
int damage )
{
unsigned ang;
int saved;
player_t* player;
fixed_t thrust;
int temp;
if ( !(target->flags & MF_SHOOTABLE) )
return; // shouldn't happen...
if (target->health <= 0)
return;
if ( target->flags & MF_SKULLFLY )
{
target->momx = target->momy = target->momz = 0;
}
player = target->player;
if (player && gameskill == sk_baby)
damage >>= 1; // take half damage in trainer mode
// Some close combat weapons should not
// inflict thrust and push the victim out of reach,
// thus kick away unless using the chainsaw.
if (inflictor
&& !(target->flags & MF_NOCLIP)
&& (!source
|| !source->player
|| source->player->readyweapon != wp_chainsaw))
{
ang = R_PointToAngle2 ( inflictor->x,
inflictor->y,
target->x,
target->y);
thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
// make fall forwards sometimes
if ( damage < 40
&& damage > target->health
&& target->z - inflictor->z > 64*FRACUNIT
&& (P_Random ()&1) )
{
ang += ANG180;
thrust *= 4;
}
ang >>= ANGLETOFINESHIFT;
target->momx += FixedMul (thrust, finecosine[ang]);
target->momy += FixedMul (thrust, finesine[ang]);
}
// player specific
if (player)
{
// end of game hell hack
if (target->subsector->sector->special == 11
&& damage >= target->health)
{
damage = target->health - 1;
}
// Below certain threshold,
// ignore damage in GOD mode, or with INVUL power.
if ( damage < 1000
&& ( (player->cheats&CF_GODMODE)
|| player->powers[pw_invulnerability] ) )
{
return;
}
if (player->armortype)
{
if (player->armortype == 1)
saved = damage/3;
else
saved = damage/2;
if (player->armorpoints <= saved)
{
// armor is used up
saved = player->armorpoints;
player->armortype = 0;
}
player->armorpoints -= saved;
damage -= saved;
}
player->health -= damage; // mirror mobj health here for Dave
if (player->health < 0)
player->health = 0;
player->attacker = source;
player->damagecount += damage; // add damage after armor / invuln
if (player->damagecount > 100)
player->damagecount = 100; // teleport stomp does 10k points...
temp = damage < 100 ? damage : 100;
if (player == &players[consoleplayer])
I_Tactile (40,10,40+temp*2);
}
// do the damage
target->health -= damage;
if (target->health <= 0)
{
P_KillMobj (source, target);
return;
}
if ( (P_Random () < target->info->painchance)
&& !(target->flags&MF_SKULLFLY) )
{
target->flags |= MF_JUSTHIT; // fight back!
P_SetMobjState (target, target->info->painstate);
}
target->reactiontime = 0; // we're awake now...
if ( (!target->threshold || target->type == MT_VILE)
&& source && source != target
&& source->type != MT_VILE)
{
// if not intent on another player,
// chase after this one
target->target = source;
target->threshold = BASETHRESHOLD;
if (target->state == &states[target->info->spawnstate]
&& target->info->seestate != S_NULL)
P_SetMobjState (target, target->info->seestate);
}
}

38
src/DOOM/p_inter.h Normal file
View File

@ -0,0 +1,38 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __P_INTER__
#define __P_INTER__
#include "d_player.h"
doom_boolean P_GivePower(player_t*, int);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

333
src/DOOM/p_lights.c Normal file
View File

@ -0,0 +1,333 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Handle Sector base lighting effects.
// Muzzle flash?
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "m_random.h"
#include "doomdef.h"
#include "p_local.h"
#include "r_state.h" // State.
//
// FIRELIGHT FLICKER
//
//
// T_FireFlicker
//
void T_FireFlicker(fireflicker_t* flick)
{
int amount;
if (--flick->count)
return;
amount = (P_Random() & 3) * 16;
if (flick->sector->lightlevel - amount < flick->minlight)
flick->sector->lightlevel = flick->minlight;
else
flick->sector->lightlevel = flick->maxlight - amount;
flick->count = 4;
}
//
// P_SpawnFireFlicker
//
void P_SpawnFireFlicker(sector_t* sector)
{
fireflicker_t* flick;
// Note that we are resetting sector attributes.
// Nothing special about it during gameplay.
sector->special = 0;
flick = Z_Malloc(sizeof(*flick), PU_LEVSPEC, 0);
P_AddThinker(&flick->thinker);
flick->thinker.function.acp1 = (actionf_p1)T_FireFlicker;
flick->sector = sector;
flick->maxlight = sector->lightlevel;
flick->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel) + 16;
flick->count = 4;
}
//
// BROKEN LIGHT FLASHING
//
//
// T_LightFlash
// Do flashing lights.
//
void T_LightFlash(lightflash_t* flash)
{
if (--flash->count)
return;
if (flash->sector->lightlevel == flash->maxlight)
{
flash->sector->lightlevel = flash->minlight;
flash->count = (P_Random() & flash->mintime) + 1;
}
else
{
flash->sector->lightlevel = flash->maxlight;
flash->count = (P_Random() & flash->maxtime) + 1;
}
}
//
// P_SpawnLightFlash
// After the map has been loaded, scan each sector
// for specials that spawn thinkers
//
void P_SpawnLightFlash(sector_t* sector)
{
lightflash_t* flash;
// nothing special about it during gameplay
sector->special = 0;
flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);
P_AddThinker(&flash->thinker);
flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
flash->sector = sector;
flash->maxlight = sector->lightlevel;
flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
flash->maxtime = 64;
flash->mintime = 7;
flash->count = (P_Random() & flash->maxtime) + 1;
}
//
// STROBE LIGHT FLASHING
//
//
// T_StrobeFlash
//
void T_StrobeFlash(strobe_t* flash)
{
if (--flash->count)
return;
if (flash->sector->lightlevel == flash->minlight)
{
flash->sector->lightlevel = flash->maxlight;
flash->count = flash->brighttime;
}
else
{
flash->sector->lightlevel = flash->minlight;
flash->count = flash->darktime;
}
}
//
// P_SpawnStrobeFlash
// After the map has been loaded, scan each sector
// for specials that spawn thinkers
//
void P_SpawnStrobeFlash(sector_t* sector, int fastOrSlow, int inSync)
{
strobe_t* flash;
flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);
P_AddThinker(&flash->thinker);
flash->sector = sector;
flash->darktime = fastOrSlow;
flash->brighttime = STROBEBRIGHT;
flash->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
flash->maxlight = sector->lightlevel;
flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
if (flash->minlight == flash->maxlight)
flash->minlight = 0;
// nothing special about it during gameplay
sector->special = 0;
if (!inSync)
flash->count = (P_Random() & 7) + 1;
else
flash->count = 1;
}
//
// Start strobing lights (usually from a trigger)
//
void EV_StartLightStrobing(line_t* line)
{
int secnum;
sector_t* sec;
secnum = -1;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
P_SpawnStrobeFlash(sec, SLOWDARK, 0);
}
}
//
// TURN LINE'S TAG LIGHTS OFF
//
void EV_TurnTagLightsOff(line_t* line)
{
int i;
int j;
int min;
sector_t* sector;
sector_t* tsec;
line_t* templine;
sector = sectors;
for (j = 0; j < numsectors; j++, sector++)
{
if (sector->tag == line->tag)
{
min = sector->lightlevel;
for (i = 0; i < sector->linecount; i++)
{
templine = sector->lines[i];
tsec = getNextSector(templine, sector);
if (!tsec)
continue;
if (tsec->lightlevel < min)
min = tsec->lightlevel;
}
sector->lightlevel = min;
}
}
}
//
// TURN LINE'S TAG LIGHTS ON
//
void EV_LightTurnOn(line_t* line, int bright)
{
int i;
int j;
sector_t* sector;
sector_t* temp;
line_t* templine;
sector = sectors;
for (i = 0; i < numsectors; i++, sector++)
{
if (sector->tag == line->tag)
{
// bright = 0 means to search
// for highest light level
// surrounding sector
if (!bright)
{
for (j = 0; j < sector->linecount; j++)
{
templine = sector->lines[j];
temp = getNextSector(templine, sector);
if (!temp)
continue;
if (temp->lightlevel > bright)
bright = temp->lightlevel;
}
}
sector->lightlevel = bright;
}
}
}
//
// Spawn glowing light
//
void T_Glow(glow_t* g)
{
switch (g->direction)
{
case -1:
// DOWN
g->sector->lightlevel -= GLOWSPEED;
if (g->sector->lightlevel <= g->minlight)
{
g->sector->lightlevel += GLOWSPEED;
g->direction = 1;
}
break;
case 1:
// UP
g->sector->lightlevel += GLOWSPEED;
if (g->sector->lightlevel >= g->maxlight)
{
g->sector->lightlevel -= GLOWSPEED;
g->direction = -1;
}
break;
}
}
void P_SpawnGlowingLight(sector_t* sector)
{
glow_t* g;
g = Z_Malloc(sizeof(*g), PU_LEVSPEC, 0);
P_AddThinker(&g->thinker);
g->sector = sector;
g->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
g->maxlight = sector->lightlevel;
g->thinker.function.acp1 = (actionf_p1)T_Glow;
g->direction = -1;
sector->special = 0;
}

256
src/DOOM/p_local.h Normal file
View File

@ -0,0 +1,256 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Play functions, animation, global header.
//
//-----------------------------------------------------------------------------
#ifndef __P_LOCAL__
#define __P_LOCAL__
#ifndef __R_LOCAL__
#include "r_local.h"
#endif
#define FLOATSPEED (FRACUNIT*4)
#define MAXHEALTH 100
#define VIEWHEIGHT (41*FRACUNIT)
// mapblocks are used to check movement
// against lines and things
#define MAPBLOCKUNITS 128
#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT)
#define MAPBLOCKSHIFT (FRACBITS+7)
#define MAPBMASK (MAPBLOCKSIZE-1)
#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS)
// player radius for movement checking
#define PLAYERRADIUS 16*FRACUNIT
// MAXRADIUS is for precalculated sector block boxes
// the spider demon is larger,
// but we do not have any moving sectors nearby
#define MAXRADIUS 32*FRACUNIT
#define GRAVITY FRACUNIT
#define MAXMOVE (30*FRACUNIT)
#define USERANGE (64*FRACUNIT)
#define MELEERANGE (64*FRACUNIT)
#define MISSILERANGE (32*64*FRACUNIT)
// follow a player exlusively for 3 seconds
#define BASETHRESHOLD 100
//
// P_TICK
//
// both the head and tail of the thinker list
extern thinker_t thinkercap;
void P_InitThinkers(void);
void P_AddThinker(thinker_t* thinker);
void P_RemoveThinker(thinker_t* thinker);
//
// P_PSPR
//
void P_SetupPsprites(player_t* curplayer);
void P_MovePsprites(player_t* curplayer);
void P_DropWeapon(player_t* player);
//
// P_USER
//
void P_PlayerThink(player_t* player);
//
// P_MOBJ
//
#define ONFLOORZ DOOM_MININT
#define ONCEILINGZ DOOM_MAXINT
// Time interval for item respawning.
#define ITEMQUESIZE 128
extern mapthing_t itemrespawnque[ITEMQUESIZE];
extern int itemrespawntime[ITEMQUESIZE];
extern int iquehead;
extern int iquetail;
void P_RespawnSpecials(void);
mobj_t* P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
void P_RemoveMobj(mobj_t* th);
doom_boolean P_SetMobjState(mobj_t* mobj, statenum_t state);
void P_MobjThinker(mobj_t* mobj);
void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z);
void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage);
mobj_t* P_SpawnMissile(mobj_t* source, mobj_t* dest, mobjtype_t type);
void P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type);
//
// P_ENEMY
//
void P_NoiseAlert(mobj_t* target, mobj_t* emmiter);
//
// P_MAPUTL
//
typedef struct
{
fixed_t x;
fixed_t y;
fixed_t dx;
fixed_t dy;
} divline_t;
typedef struct
{
fixed_t frac; // along trace line
doom_boolean isaline;
union
{
mobj_t* thing;
line_t* line;
} d;
} intercept_t;
#define MAXINTERCEPTS 128
extern intercept_t intercepts[MAXINTERCEPTS];
extern intercept_t* intercept_p;
typedef doom_boolean(*traverser_t) (intercept_t* in);
fixed_t P_AproxDistance(fixed_t dx, fixed_t dy);
int P_PointOnLineSide(fixed_t x, fixed_t y, line_t* line);
int P_PointOnDivlineSide(fixed_t x, fixed_t y, divline_t* line);
void P_MakeDivline(line_t* li, divline_t* dl);
fixed_t P_InterceptVector(divline_t* v2, divline_t* v1);
int P_BoxOnLineSide(fixed_t* tmbox, line_t* ld);
extern fixed_t opentop;
extern fixed_t openbottom;
extern fixed_t openrange;
extern fixed_t lowfloor;
void P_LineOpening(line_t* linedef);
doom_boolean P_BlockLinesIterator(int x, int y, doom_boolean(*func)(line_t*));
doom_boolean P_BlockThingsIterator(int x, int y, doom_boolean(*func)(mobj_t*));
#define PT_ADDLINES 1
#define PT_ADDTHINGS 2
#define PT_EARLYOUT 4
extern divline_t trace;
doom_boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, doom_boolean(*trav) (intercept_t*));
void P_UnsetThingPosition(mobj_t* thing);
void P_SetThingPosition(mobj_t* thing);
//
// P_MAP
//
// If "floatok" true, move would be ok
// if within "tmfloorz - tmceilingz".
extern doom_boolean floatok;
extern fixed_t tmfloorz;
extern fixed_t tmceilingz;
extern line_t* ceilingline;
doom_boolean P_CheckPosition(mobj_t* thing, fixed_t x, fixed_t y);
doom_boolean P_TryMove(mobj_t* thing, fixed_t x, fixed_t y);
doom_boolean P_TeleportMove(mobj_t* thing, fixed_t x, fixed_t y);
void P_SlideMove(mobj_t* mo);
doom_boolean P_CheckSight(mobj_t* t1, mobj_t* t2);
void P_UseLines(player_t* player);
doom_boolean P_ChangeSector(sector_t* sector, doom_boolean crunch);
extern mobj_t* linetarget; // who got hit (or 0)
fixed_t P_AimLineAttack(mobj_t* t1, angle_t angle, fixed_t distance);
void P_LineAttack(mobj_t* t1, angle_t angle, fixed_t distance, fixed_t slope, int damage);
void P_RadiusAttack(mobj_t* spot, mobj_t* source, int damage);
//
// P_SETUP
//
extern byte* rejectmatrix; // for fast sight rejection
extern short* blockmaplump; // offsets in blockmap are from here
extern short* blockmap;
extern int bmapwidth;
extern int bmapheight; // in mapblocks
extern fixed_t bmaporgx;
extern fixed_t bmaporgy; // origin of block map
extern mobj_t** blocklinks; // for thing chains
//
// P_INTER
//
extern int maxammo[NUMAMMO];
extern int clipammo[NUMAMMO];
void P_TouchSpecialThing(mobj_t* special, mobj_t* toucher);
void P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage);
//
// P_SPEC
//
#include "p_spec.h"
#endif // __P_LOCAL__
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

1291
src/DOOM/p_map.c Normal file

File diff suppressed because it is too large Load Diff

788
src/DOOM/p_maputl.c Normal file
View File

@ -0,0 +1,788 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Movement/collision utility functions,
// as used by function in p_map.c.
// BLOCKMAP Iterator functions,
// and some PIT_* functions to use for iteration.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "m_bbox.h"
#include "doomdef.h"
#include "p_local.h"
#include "r_state.h" // State.
fixed_t opentop;
fixed_t openbottom;
fixed_t openrange;
fixed_t lowfloor;
intercept_t intercepts[MAXINTERCEPTS];
intercept_t* intercept_p;
divline_t trace;
doom_boolean earlyout;
int ptflags;
//
// P_AproxDistance
// Gives an estimation of distance (not exact)
//
fixed_t P_AproxDistance(fixed_t dx, fixed_t dy)
{
dx = doom_abs(dx);
dy = doom_abs(dy);
if (dx < dy)
return dx + dy - (dx >> 1);
return dx + dy - (dy >> 1);
}
//
// P_PointOnLineSide
// Returns 0 or 1
//
int P_PointOnLineSide(fixed_t x, fixed_t y, line_t* line)
{
fixed_t dx;
fixed_t dy;
fixed_t left;
fixed_t right;
if (!line->dx)
{
if (x <= line->v1->x)
return line->dy > 0;
return line->dy < 0;
}
if (!line->dy)
{
if (y <= line->v1->y)
return line->dx < 0;
return line->dx > 0;
}
dx = (x - line->v1->x);
dy = (y - line->v1->y);
left = FixedMul(line->dy >> FRACBITS, dx);
right = FixedMul(dy, line->dx >> FRACBITS);
if (right < left)
return 0; // front side
return 1; // back side
}
//
// P_BoxOnLineSide
// Considers the line to be infinite
// Returns side 0 or 1, -1 if box crosses the line.
//
int P_BoxOnLineSide(fixed_t* tmbox, line_t* ld)
{
int p1;
int p2;
switch (ld->slopetype)
{
case ST_HORIZONTAL:
p1 = tmbox[BOXTOP] > ld->v1->y;
p2 = tmbox[BOXBOTTOM] > ld->v1->y;
if (ld->dx < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_VERTICAL:
p1 = tmbox[BOXRIGHT] < ld->v1->x;
p2 = tmbox[BOXLEFT] < ld->v1->x;
if (ld->dy < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_POSITIVE:
p1 = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld);
p2 = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
break;
case ST_NEGATIVE:
p1 = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
p2 = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
break;
}
if (p1 == p2)
return p1;
return -1;
}
//
// P_PointOnDivlineSide
// Returns 0 or 1.
//
int P_PointOnDivlineSide(fixed_t x, fixed_t y, divline_t* line)
{
fixed_t dx;
fixed_t dy;
fixed_t left;
fixed_t right;
if (!line->dx)
{
if (x <= line->x)
return line->dy > 0;
return line->dy < 0;
}
if (!line->dy)
{
if (y <= line->y)
return line->dx < 0;
return line->dx > 0;
}
dx = (x - line->x);
dy = (y - line->y);
// try to quickly decide by looking at sign bits
if ((line->dy ^ line->dx ^ dx ^ dy) & 0x80000000)
{
if ((line->dy ^ dx) & 0x80000000)
return 1; // (left is negative)
return 0;
}
left = FixedMul(line->dy >> 8, dx >> 8);
right = FixedMul(dy >> 8, line->dx >> 8);
if (right < left)
return 0; // front side
return 1; // back side
}
//
// P_MakeDivline
//
void P_MakeDivline(line_t* li, divline_t* dl)
{
dl->x = li->v1->x;
dl->y = li->v1->y;
dl->dx = li->dx;
dl->dy = li->dy;
}
//
// P_InterceptVector
// Returns the fractional intercept point
// along the first divline.
// This is only called by the addthings
// and addlines traversers.
//
fixed_t P_InterceptVector(divline_t* v2, divline_t* v1)
{
fixed_t frac;
fixed_t num;
fixed_t den;
den = FixedMul(v1->dy >> 8, v2->dx) - FixedMul(v1->dx >> 8, v2->dy);
if (den == 0)
return 0;
// I_Error ("P_InterceptVector: parallel");
num =
FixedMul((v1->x - v2->x) >> 8, v1->dy)
+ FixedMul((v2->y - v1->y) >> 8, v1->dx);
frac = FixedDiv(num, den);
return frac;
}
//
// P_LineOpening
// Sets opentop and openbottom to the window
// through a two sided line.
// OPTIMIZE: keep this precalculated
//
void P_LineOpening(line_t* linedef)
{
sector_t* front;
sector_t* back;
if (linedef->sidenum[1] == -1)
{
// single sided line
openrange = 0;
return;
}
front = linedef->frontsector;
back = linedef->backsector;
if (front->ceilingheight < back->ceilingheight)
opentop = front->ceilingheight;
else
opentop = back->ceilingheight;
if (front->floorheight > back->floorheight)
{
openbottom = front->floorheight;
lowfloor = back->floorheight;
}
else
{
openbottom = back->floorheight;
lowfloor = front->floorheight;
}
openrange = opentop - openbottom;
}
//
// THING POSITION SETTING
//
//
// P_UnsetThingPosition
// Unlinks a thing from block map and sectors.
// On each position change, BLOCKMAP and other
// lookups maintaining lists ot things inside
// these structures need to be updated.
//
void P_UnsetThingPosition(mobj_t* thing)
{
int blockx;
int blocky;
if (!(thing->flags & MF_NOSECTOR))
{
// inert things don't need to be in blockmap?
// unlink from subsector
if (thing->snext)
thing->snext->sprev = thing->sprev;
if (thing->sprev)
thing->sprev->snext = thing->snext;
else
thing->subsector->sector->thinglist = thing->snext;
}
if (!(thing->flags & MF_NOBLOCKMAP))
{
// inert things don't need to be in blockmap
// unlink from block map
if (thing->bnext)
thing->bnext->bprev = thing->bprev;
if (thing->bprev)
thing->bprev->bnext = thing->bnext;
else
{
blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT;
blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT;
if (blockx >= 0 && blockx < bmapwidth
&& blocky >= 0 && blocky < bmapheight)
{
blocklinks[blocky * bmapwidth + blockx] = thing->bnext;
}
}
}
}
//
// P_SetThingPosition
// Links a thing into both a block and a subsector
// based on it's x y.
// Sets thing->subsector properly
//
void P_SetThingPosition(mobj_t* thing)
{
subsector_t* ss;
sector_t* sec;
int blockx;
int blocky;
mobj_t** link;
// link into subsector
ss = R_PointInSubsector(thing->x, thing->y);
thing->subsector = ss;
if (!(thing->flags & MF_NOSECTOR))
{
// invisible things don't go into the sector links
sec = ss->sector;
thing->sprev = 0;
thing->snext = sec->thinglist;
if (sec->thinglist)
sec->thinglist->sprev = thing;
sec->thinglist = thing;
}
// link into blockmap
if (!(thing->flags & MF_NOBLOCKMAP))
{
// inert things don't need to be in blockmap
blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT;
blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT;
if (blockx >= 0
&& blockx < bmapwidth
&& blocky >= 0
&& blocky < bmapheight)
{
link = &blocklinks[blocky * bmapwidth + blockx];
thing->bprev = 0;
thing->bnext = *link;
if (*link)
(*link)->bprev = thing;
*link = thing;
}
else
{
// thing is off the map
thing->bnext = thing->bprev = 0;
}
}
}
//
// BLOCK MAP ITERATORS
// For each line/thing in the given mapblock,
// call the passed PIT_* function.
// If the function returns false,
// exit with false without checking anything else.
//
//
// P_BlockLinesIterator
// The validcount flags are used to avoid checking lines
// that are marked in multiple mapblocks,
// so increment validcount before the first call
// to P_BlockLinesIterator, then make one or more calls
// to it.
//
doom_boolean P_BlockLinesIterator(int x, int y, doom_boolean(*func)(line_t*))
{
int offset;
short* list;
line_t* ld;
if (x < 0
|| y < 0
|| x >= bmapwidth
|| y >= bmapheight)
{
return true;
}
offset = y * bmapwidth + x;
offset = *(blockmap + offset);
for (list = blockmaplump + offset; *list != -1; list++)
{
ld = &lines[*list];
if (ld->validcount == validcount)
continue; // line has already been checked
ld->validcount = validcount;
if (!func(ld))
return false;
}
return true; // everything was checked
}
//
// P_BlockThingsIterator
//
doom_boolean P_BlockThingsIterator(int x, int y, doom_boolean(*func)(mobj_t*))
{
mobj_t* mobj;
if (x < 0
|| y < 0
|| x >= bmapwidth
|| y >= bmapheight)
{
return true;
}
for (mobj = blocklinks[y * bmapwidth + x];
mobj;
mobj = mobj->bnext)
{
if (!func(mobj))
return false;
}
return true;
}
//
// INTERCEPT ROUTINES
//
//
// PIT_AddLineIntercepts.
// Looks for lines in the given block
// that intercept the given trace
// to add to the intercepts list.
//
// A line is crossed if its endpoints
// are on opposite sides of the trace.
// Returns true if earlyout and a solid line hit.
//
doom_boolean PIT_AddLineIntercepts(line_t* ld)
{
int s1;
int s2;
fixed_t frac;
divline_t dl;
// avoid precision problems with two routines
if (trace.dx > FRACUNIT * 16
|| trace.dy > FRACUNIT * 16
|| trace.dx < -FRACUNIT * 16
|| trace.dy < -FRACUNIT * 16)
{
s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace);
s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace);
}
else
{
s1 = P_PointOnLineSide(trace.x, trace.y, ld);
s2 = P_PointOnLineSide(trace.x + trace.dx, trace.y + trace.dy, ld);
}
if (s1 == s2)
return true; // line isn't crossed
// hit the line
P_MakeDivline(ld, &dl);
frac = P_InterceptVector(&trace, &dl);
if (frac < 0)
return true; // behind source
// try to early out the check
if (earlyout
&& frac < FRACUNIT
&& !ld->backsector)
{
return false; // stop checking
}
intercept_p->frac = frac;
intercept_p->isaline = true;
intercept_p->d.line = ld;
intercept_p++;
return true; // continue
}
//
// PIT_AddThingIntercepts
//
doom_boolean PIT_AddThingIntercepts(mobj_t* thing)
{
fixed_t x1;
fixed_t y1;
fixed_t x2;
fixed_t y2;
int s1;
int s2;
doom_boolean tracepositive;
divline_t dl;
fixed_t frac;
tracepositive = (trace.dx ^ trace.dy) > 0;
// check a corner to corner crossection for hit
if (tracepositive)
{
x1 = thing->x - thing->radius;
y1 = thing->y + thing->radius;
x2 = thing->x + thing->radius;
y2 = thing->y - thing->radius;
}
else
{
x1 = thing->x - thing->radius;
y1 = thing->y - thing->radius;
x2 = thing->x + thing->radius;
y2 = thing->y + thing->radius;
}
s1 = P_PointOnDivlineSide(x1, y1, &trace);
s2 = P_PointOnDivlineSide(x2, y2, &trace);
if (s1 == s2)
return true; // line isn't crossed
dl.x = x1;
dl.y = y1;
dl.dx = x2 - x1;
dl.dy = y2 - y1;
frac = P_InterceptVector(&trace, &dl);
if (frac < 0)
return true; // behind source
intercept_p->frac = frac;
intercept_p->isaline = false;
intercept_p->d.thing = thing;
intercept_p++;
return true; // keep going
}
//
// P_TraverseIntercepts
// Returns true if the traverser function returns true
// for all lines.
//
doom_boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac)
{
int count;
fixed_t dist;
intercept_t* scan;
intercept_t* in;
count = (int)(intercept_p - intercepts);
in = 0; // shut up compiler warning
while (count--)
{
dist = DOOM_MAXINT;
for (scan = intercepts; scan < intercept_p; scan++)
{
if (scan->frac < dist)
{
dist = scan->frac;
in = scan;
}
}
if (dist > maxfrac)
return true; // checked everything in range
#if 0 // UNUSED
{
// don't check these yet, there may be others inserted
in = scan = intercepts;
for (scan = intercepts; scan < intercept_p; scan++)
if (scan->frac > maxfrac)
*in++ = *scan;
intercept_p = in;
return false;
}
#endif
if (!func(in))
return false; // don't bother going farther
in->frac = DOOM_MAXINT;
}
return true; // everything was traversed
}
//
// P_PathTraverse
// Traces a line from x1,y1 to x2,y2,
// calling the traverser function for each.
// Returns true if the traverser function returns true
// for all lines.
//
doom_boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, doom_boolean(*trav) (intercept_t*))
{
fixed_t xt1;
fixed_t yt1;
fixed_t xt2;
fixed_t yt2;
fixed_t xstep;
fixed_t ystep;
fixed_t partial;
fixed_t xintercept;
fixed_t yintercept;
int mapx;
int mapy;
int mapxstep;
int mapystep;
int count;
earlyout = flags & PT_EARLYOUT;
validcount++;
intercept_p = intercepts;
if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0)
y1 += FRACUNIT; // don't side exactly on a line
trace.x = x1;
trace.y = y1;
trace.dx = x2 - x1;
trace.dy = y2 - y1;
x1 -= bmaporgx;
y1 -= bmaporgy;
xt1 = x1 >> MAPBLOCKSHIFT;
yt1 = y1 >> MAPBLOCKSHIFT;
x2 -= bmaporgx;
y2 -= bmaporgy;
xt2 = x2 >> MAPBLOCKSHIFT;
yt2 = y2 >> MAPBLOCKSHIFT;
if (xt2 > xt1)
{
mapxstep = 1;
partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1));
ystep = FixedDiv(y2 - y1, doom_abs(x2 - x1));
}
else if (xt2 < xt1)
{
mapxstep = -1;
partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1);
ystep = FixedDiv(y2 - y1, doom_abs(x2 - x1));
}
else
{
mapxstep = 0;
partial = FRACUNIT;
ystep = 256 * FRACUNIT;
}
yintercept = (y1 >> MAPBTOFRAC) + FixedMul(partial, ystep);
if (yt2 > yt1)
{
mapystep = 1;
partial = FRACUNIT - ((y1 >> MAPBTOFRAC) & (FRACUNIT - 1));
xstep = FixedDiv(x2 - x1, doom_abs(y2 - y1));
}
else if (yt2 < yt1)
{
mapystep = -1;
partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1);
xstep = FixedDiv(x2 - x1, doom_abs(y2 - y1));
}
else
{
mapystep = 0;
partial = FRACUNIT;
xstep = 256 * FRACUNIT;
}
xintercept = (x1 >> MAPBTOFRAC) + FixedMul(partial, xstep);
// Step through map blocks.
// Count is present to prevent a round off error
// from skipping the break.
mapx = xt1;
mapy = yt1;
for (count = 0; count < 64; count++)
{
if (flags & PT_ADDLINES)
{
if (!P_BlockLinesIterator(mapx, mapy, PIT_AddLineIntercepts))
return false; // early out
}
if (flags & PT_ADDTHINGS)
{
if (!P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts))
return false; // early out
}
if (mapx == xt2
&& mapy == yt2)
{
break;
}
if ((yintercept >> FRACBITS) == mapy)
{
yintercept += ystep;
mapx += mapxstep;
}
else if ((xintercept >> FRACBITS) == mapx)
{
xintercept += xstep;
mapy += mapystep;
}
}
// go through the sorted list
return P_TraverseIntercepts(trav, FRACUNIT);
}

961
src/DOOM/p_mobj.c Normal file
View File

@ -0,0 +1,961 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Moving object handling. Spawn functions.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "i_system.h"
#include "z_zone.h"
#include "m_random.h"
#include "doomdef.h"
#include "p_local.h"
#include "sounds.h"
#include "st_stuff.h"
#include "hu_stuff.h"
#include "s_sound.h"
#include "doomstat.h"
#define STOPSPEED 0x1000
#define FRICTION 0xe800
//
// P_SetMobjState
// Returns true if the mobj is still present.
//
mapthing_t itemrespawnque[ITEMQUESIZE];
int itemrespawntime[ITEMQUESIZE];
int iquehead;
int iquetail;
extern fixed_t attackrange;
void G_PlayerReborn(int player);
void P_SpawnMapThing(mapthing_t* mthing);
doom_boolean P_SetMobjState(mobj_t* mobj, statenum_t state)
{
state_t* st;
do
{
if (state == S_NULL)
{
mobj->state = (state_t*)S_NULL;
P_RemoveMobj(mobj);
return false;
}
st = &states[state];
mobj->state = st;
mobj->tics = st->tics;
mobj->sprite = st->sprite;
mobj->frame = st->frame;
// Modified handling.
// Call action functions when the state is set
if (st->action.acp1)
st->action.acp1(mobj);
state = st->nextstate;
} while (!mobj->tics);
return true;
}
//
// P_ExplodeMissile
//
void P_ExplodeMissile(mobj_t* mo)
{
mo->momx = mo->momy = mo->momz = 0;
P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
mo->tics -= P_Random() & 3;
if (mo->tics < 1)
mo->tics = 1;
mo->flags &= ~MF_MISSILE;
if (mo->info->deathsound)
S_StartSound(mo, mo->info->deathsound);
}
//
// P_XYMovement
//
void P_XYMovement(mobj_t* mo)
{
fixed_t ptryx;
fixed_t ptryy;
player_t* player;
fixed_t xmove;
fixed_t ymove;
if (!mo->momx && !mo->momy)
{
if (mo->flags & MF_SKULLFLY)
{
// the skull slammed into something
mo->flags &= ~MF_SKULLFLY;
mo->momx = mo->momy = mo->momz = 0;
P_SetMobjState(mo, mo->info->spawnstate);
}
return;
}
player = mo->player;
if (mo->momx > MAXMOVE)
mo->momx = MAXMOVE;
else if (mo->momx < -MAXMOVE)
mo->momx = -MAXMOVE;
if (mo->momy > MAXMOVE)
mo->momy = MAXMOVE;
else if (mo->momy < -MAXMOVE)
mo->momy = -MAXMOVE;
xmove = mo->momx;
ymove = mo->momy;
do
{
if (xmove > MAXMOVE / 2 || ymove > MAXMOVE / 2)
{
ptryx = mo->x + xmove / 2;
ptryy = mo->y + ymove / 2;
xmove >>= 1;
ymove >>= 1;
}
else
{
ptryx = mo->x + xmove;
ptryy = mo->y + ymove;
xmove = ymove = 0;
}
if (!P_TryMove(mo, ptryx, ptryy))
{
// blocked move
if (mo->player)
{ // try to slide along it
P_SlideMove(mo);
}
else if (mo->flags & MF_MISSILE)
{
// explode a missile
if (ceilingline &&
ceilingline->backsector &&
ceilingline->backsector->ceilingpic == skyflatnum)
{
// Hack to prevent missiles exploding
// against the sky.
// Does not handle sky floors.
P_RemoveMobj(mo);
return;
}
P_ExplodeMissile(mo);
}
else
mo->momx = mo->momy = 0;
}
} while (xmove || ymove);
// slow down
if (player && player->cheats & CF_NOMOMENTUM)
{
// debug option for no sliding at all
mo->momx = mo->momy = 0;
return;
}
if (mo->flags & (MF_MISSILE | MF_SKULLFLY))
return; // no friction for missiles ever
if (mo->z > mo->floorz)
return; // no friction when airborne
if (mo->flags & MF_CORPSE)
{
// do not stop sliding
// if halfway off a step with some momentum
if (mo->momx > FRACUNIT / 4
|| mo->momx < -FRACUNIT / 4
|| mo->momy > FRACUNIT / 4
|| mo->momy < -FRACUNIT / 4)
{
if (mo->floorz != mo->subsector->sector->floorheight)
return;
}
}
if (mo->momx > -STOPSPEED
&& mo->momx < STOPSPEED
&& mo->momy > -STOPSPEED
&& mo->momy < STOPSPEED
&& (!player
|| (player->cmd.forwardmove == 0
&& player->cmd.sidemove == 0)))
{
// if in a walking frame, stop moving
if (player && (unsigned)((player->mo->state - states) - S_PLAY_RUN1) < 4)
P_SetMobjState(player->mo, S_PLAY);
mo->momx = 0;
mo->momy = 0;
}
else
{
mo->momx = FixedMul(mo->momx, FRICTION);
mo->momy = FixedMul(mo->momy, FRICTION);
}
}
//
// P_ZMovement
//
void P_ZMovement(mobj_t* mo)
{
fixed_t dist;
fixed_t delta;
// check for smooth step up
if (mo->player && mo->z < mo->floorz)
{
mo->player->viewheight -= mo->floorz - mo->z;
mo->player->deltaviewheight
= (VIEWHEIGHT - mo->player->viewheight) >> 3;
}
// adjust height
mo->z += mo->momz;
if (mo->flags & MF_FLOAT
&& mo->target)
{
// float down towards target if too close
if (!(mo->flags & MF_SKULLFLY)
&& !(mo->flags & MF_INFLOAT))
{
dist = P_AproxDistance(mo->x - mo->target->x,
mo->y - mo->target->y);
delta = (mo->target->z + (mo->height >> 1)) - mo->z;
if (delta < 0 && dist < -(delta * 3))
mo->z -= FLOATSPEED;
else if (delta > 0 && dist < (delta * 3))
mo->z += FLOATSPEED;
}
}
// clip movement
if (mo->z <= mo->floorz)
{
// hit the floor
// Note (id):
// somebody left this after the setting momz to 0,
// kinda useless there.
if (mo->flags & MF_SKULLFLY)
{
// the skull slammed into something
mo->momz = -mo->momz;
}
if (mo->momz < 0)
{
if (mo->player
&& mo->momz < -GRAVITY * 8)
{
// Squat down.
// Decrease viewheight for a moment
// after hitting the ground (hard),
// and utter appropriate sound.
mo->player->deltaviewheight = mo->momz >> 3;
S_StartSound(mo, sfx_oof);
}
mo->momz = 0;
}
mo->z = mo->floorz;
if ((mo->flags & MF_MISSILE)
&& !(mo->flags & MF_NOCLIP))
{
P_ExplodeMissile(mo);
return;
}
}
else if (!(mo->flags & MF_NOGRAVITY))
{
if (mo->momz == 0)
mo->momz = -GRAVITY * 2;
else
mo->momz -= GRAVITY;
}
if (mo->z + mo->height > mo->ceilingz)
{
// hit the ceiling
if (mo->momz > 0)
mo->momz = 0;
{
mo->z = mo->ceilingz - mo->height;
}
if (mo->flags & MF_SKULLFLY)
{ // the skull slammed into something
mo->momz = -mo->momz;
}
if ((mo->flags & MF_MISSILE)
&& !(mo->flags & MF_NOCLIP))
{
P_ExplodeMissile(mo);
return;
}
}
}
//
// P_NightmareRespawn
//
void P_NightmareRespawn(mobj_t* mobj)
{
fixed_t x;
fixed_t y;
fixed_t z;
subsector_t* ss;
mobj_t* mo;
mapthing_t* mthing;
x = mobj->spawnpoint.x << FRACBITS;
y = mobj->spawnpoint.y << FRACBITS;
// somthing is occupying it's position?
if (!P_CheckPosition(mobj, x, y))
return; // no respwan
// spawn a teleport fog at old spot
// because of removal of the body?
mo = P_SpawnMobj(mobj->x,
mobj->y,
mobj->subsector->sector->floorheight, MT_TFOG);
// initiate teleport sound
S_StartSound(mo, sfx_telept);
// spawn a teleport fog at the new spot
ss = R_PointInSubsector(x, y);
mo = P_SpawnMobj(x, y, ss->sector->floorheight, MT_TFOG);
S_StartSound(mo, sfx_telept);
// spawn the new monster
mthing = &mobj->spawnpoint;
// spawn it
if (mobj->info->flags & MF_SPAWNCEILING)
z = ONCEILINGZ;
else
z = ONFLOORZ;
// inherit attributes from deceased one
mo = P_SpawnMobj(x, y, z, mobj->type);
mo->spawnpoint = mobj->spawnpoint;
mo->angle = ANG45 * (mthing->angle / 45);
if (mthing->options & MTF_AMBUSH)
mo->flags |= MF_AMBUSH;
mo->reactiontime = 18;
// remove the old monster,
P_RemoveMobj(mobj);
}
//
// P_MobjThinker
//
void P_MobjThinker(mobj_t* mobj)
{
// momentum movement
if (mobj->momx
|| mobj->momy
|| (mobj->flags & MF_SKULLFLY))
{
P_XYMovement(mobj);
// FIXME: decent NOP/0/Nil function pointer please.
if (mobj->thinker.function.acv == (actionf_v)(-1))
return; // mobj was removed
}
if ((mobj->z != mobj->floorz)
|| mobj->momz)
{
P_ZMovement(mobj);
// FIXME: decent NOP/0/Nil function pointer please.
if (mobj->thinker.function.acv == (actionf_v)(-1))
return; // mobj was removed
}
// cycle through states,
// calling action functions at transitions
if (mobj->tics != -1)
{
mobj->tics--;
// you can cycle through multiple states in a tic
if (!mobj->tics)
if (!P_SetMobjState(mobj, mobj->state->nextstate))
return; // freed itself
}
else
{
// check for nightmare respawn
if (!(mobj->flags & MF_COUNTKILL))
return;
if (!respawnmonsters)
return;
mobj->movecount++;
if (mobj->movecount < 12 * 35)
return;
if (leveltime & 31)
return;
if (P_Random() > 4)
return;
P_NightmareRespawn(mobj);
}
}
//
// P_SpawnMobj
//
mobj_t* P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{
mobj_t* mobj;
state_t* st;
mobjinfo_t* info;
mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, 0);
doom_memset(mobj, 0, sizeof(*mobj));
info = &mobjinfo[type];
mobj->type = type;
mobj->info = info;
mobj->x = x;
mobj->y = y;
mobj->radius = info->radius;
mobj->height = info->height;
mobj->flags = info->flags;
mobj->health = info->spawnhealth;
if (gameskill != sk_nightmare)
mobj->reactiontime = info->reactiontime;
mobj->lastlook = P_Random() % MAXPLAYERS;
// do not set the state with P_SetMobjState,
// because action routines can not be called yet
st = &states[info->spawnstate];
mobj->state = st;
mobj->tics = st->tics;
mobj->sprite = st->sprite;
mobj->frame = st->frame;
// set subsector and/or block links
P_SetThingPosition(mobj);
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
if (z == ONFLOORZ)
mobj->z = mobj->floorz;
else if (z == ONCEILINGZ)
mobj->z = mobj->ceilingz - mobj->info->height;
else
mobj->z = z;
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
P_AddThinker(&mobj->thinker);
return mobj;
}
//
// P_RemoveMobj
//
void P_RemoveMobj(mobj_t* mobj)
{
if ((mobj->flags & MF_SPECIAL)
&& !(mobj->flags & MF_DROPPED)
&& (mobj->type != MT_INV)
&& (mobj->type != MT_INS))
{
itemrespawnque[iquehead] = mobj->spawnpoint;
itemrespawntime[iquehead] = leveltime;
iquehead = (iquehead + 1) & (ITEMQUESIZE - 1);
// lose one off the end?
if (iquehead == iquetail)
iquetail = (iquetail + 1) & (ITEMQUESIZE - 1);
}
// unlink from sector and block lists
P_UnsetThingPosition(mobj);
// stop any playing sound
S_StopSound(mobj);
// free block
P_RemoveThinker((thinker_t*)mobj);
}
//
// P_RespawnSpecials
//
void P_RespawnSpecials(void)
{
fixed_t x;
fixed_t y;
fixed_t z;
subsector_t* ss;
mobj_t* mo;
mapthing_t* mthing;
int i;
// only respawn items in deathmatch
if (deathmatch != 2)
return; //
// nothing left to respawn?
if (iquehead == iquetail)
return;
// wait at least 30 seconds
if (leveltime - itemrespawntime[iquetail] < 30 * 35)
return;
mthing = &itemrespawnque[iquetail];
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
// spawn a teleport fog at the new spot
ss = R_PointInSubsector(x, y);
mo = P_SpawnMobj(x, y, ss->sector->floorheight, MT_IFOG);
S_StartSound(mo, sfx_itmbk);
// find which type to spawn
for (i = 0; i < NUMMOBJTYPES; i++)
{
if (mthing->type == mobjinfo[i].doomednum)
break;
}
// spawn it
if (mobjinfo[i].flags & MF_SPAWNCEILING)
z = ONCEILINGZ;
else
z = ONFLOORZ;
mo = P_SpawnMobj(x, y, z, i);
mo->spawnpoint = *mthing;
mo->angle = ANG45 * (mthing->angle / 45);
// pull it from the que
iquetail = (iquetail + 1) & (ITEMQUESIZE - 1);
}
//
// P_SpawnPlayer
// Called when a player is spawned on the level.
// Most of the player structure stays unchanged
// between levels.
//
void P_SpawnPlayer(mapthing_t* mthing)
{
player_t* p;
fixed_t x;
fixed_t y;
fixed_t z;
mobj_t* mobj;
int i;
// not playing?
if (!playeringame[mthing->type - 1])
return;
p = &players[mthing->type - 1];
if (p->playerstate == PST_REBORN)
G_PlayerReborn(mthing->type - 1);
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
z = ONFLOORZ;
mobj = P_SpawnMobj(x, y, z, MT_PLAYER);
// set color translations for player sprites
if (mthing->type > 1)
mobj->flags |= (mthing->type - 1) << MF_TRANSSHIFT;
mobj->angle = ANG45 * (mthing->angle / 45);
mobj->player = p;
mobj->health = p->health;
p->mo = mobj;
p->playerstate = PST_LIVE;
p->refire = 0;
p->message = 0;
p->damagecount = 0;
p->bonuscount = 0;
p->extralight = 0;
p->fixedcolormap = 0;
p->viewheight = VIEWHEIGHT;
// setup gun psprite
P_SetupPsprites(p);
// give all cards in death match mode
if (deathmatch)
for (i = 0; i < NUMCARDS; i++)
p->cards[i] = true;
if (mthing->type - 1 == consoleplayer)
{
// wake up the status bar
ST_Start();
// wake up the heads up text
HU_Start();
}
}
//
// P_SpawnMapThing
// The fields of the mapthing should
// already be in host byte order.
//
void P_SpawnMapThing(mapthing_t* mthing)
{
int i;
int bit;
mobj_t* mobj;
fixed_t x;
fixed_t y;
fixed_t z;
// count deathmatch start positions
if (mthing->type == 11)
{
if (deathmatch_p < &deathmatchstarts[10])
{
doom_memcpy(deathmatch_p, mthing, sizeof(*mthing));
deathmatch_p++;
}
return;
}
// check for players specially
if (mthing->type <= 4)
{
// save spots for respawning in network games
playerstarts[mthing->type - 1] = *mthing;
if (!deathmatch)
P_SpawnPlayer(mthing);
return;
}
// check for apropriate skill level
if (!netgame && (mthing->options & 16))
return;
if (gameskill == sk_baby)
bit = 1;
else if (gameskill == sk_nightmare)
bit = 4;
else
bit = 1 << (gameskill - 1);
if (!(mthing->options & bit))
return;
// find which type to spawn
for (i = 0; i < NUMMOBJTYPES; i++)
if (mthing->type == mobjinfo[i].doomednum)
break;
if (i == NUMMOBJTYPES)
{
//I_Error("Error: P_SpawnMapThing: Unknown type %i at (%i, %i)",
// mthing->type,
// mthing->x, mthing->y);
doom_strcpy(error_buf, "Error: P_SpawnMapThing: Unknown type ");
doom_concat(error_buf, doom_itoa(mthing->type, 10));
doom_concat(error_buf, " at (");
doom_concat(error_buf, doom_itoa(mthing->x, 10));
doom_concat(error_buf, ", ");
doom_concat(error_buf, doom_itoa(mthing->y, 10));
doom_concat(error_buf, ")");
I_Error(error_buf);
}
// don't spawn keycards and players in deathmatch
if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
return;
// don't spawn any monsters if -nomonsters
if (nomonsters
&& (i == MT_SKULL
|| (mobjinfo[i].flags & MF_COUNTKILL)))
{
return;
}
// spawn it
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
if (mobjinfo[i].flags & MF_SPAWNCEILING)
z = ONCEILINGZ;
else
z = ONFLOORZ;
mobj = P_SpawnMobj(x, y, z, i);
mobj->spawnpoint = *mthing;
if (mobj->tics > 0)
mobj->tics = 1 + (P_Random() % mobj->tics);
if (mobj->flags & MF_COUNTKILL)
totalkills++;
if (mobj->flags & MF_COUNTITEM)
totalitems++;
mobj->angle = ANG45 * (mthing->angle / 45);
if (mthing->options & MTF_AMBUSH)
mobj->flags |= MF_AMBUSH;
}
//
// GAME SPAWN FUNCTIONS
//
//
// P_SpawnPuff
//
void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
{
mobj_t* th;
z += ((P_Random() - P_Random()) << 10);
th = P_SpawnMobj(x, y, z, MT_PUFF);
th->momz = FRACUNIT;
th->tics -= P_Random() & 3;
if (th->tics < 1)
th->tics = 1;
// don't make punches spark on the wall
if (attackrange == MELEERANGE)
P_SetMobjState(th, S_PUFF3);
}
//
// P_SpawnBlood
//
void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage)
{
mobj_t* th;
z += ((P_Random() - P_Random()) << 10);
th = P_SpawnMobj(x, y, z, MT_BLOOD);
th->momz = FRACUNIT * 2;
th->tics -= P_Random() & 3;
if (th->tics < 1)
th->tics = 1;
if (damage <= 12 && damage >= 9)
P_SetMobjState(th, S_BLOOD2);
else if (damage < 9)
P_SetMobjState(th, S_BLOOD3);
}
//
// P_CheckMissileSpawn
// Moves the missile forward a bit
// and possibly explodes it right there.
//
void P_CheckMissileSpawn(mobj_t* th)
{
th->tics -= P_Random() & 3;
if (th->tics < 1)
th->tics = 1;
// move a little forward so an angle can
// be computed if it immediately explodes
th->x += (th->momx >> 1);
th->y += (th->momy >> 1);
th->z += (th->momz >> 1);
if (!P_TryMove(th, th->x, th->y))
P_ExplodeMissile(th);
}
//
// P_SpawnMissile
//
mobj_t* P_SpawnMissile(mobj_t* source, mobj_t* dest, mobjtype_t type)
{
mobj_t* th;
angle_t an;
int dist;
th = P_SpawnMobj(source->x,
source->y,
source->z + 4 * 8 * FRACUNIT, type);
if (th->info->seesound)
S_StartSound(th, th->info->seesound);
th->target = source; // where it came from
an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
// fuzzy player
if (dest->flags & MF_SHADOW)
an += (P_Random() - P_Random()) << 20;
th->angle = an;
an >>= ANGLETOFINESHIFT;
th->momx = FixedMul(th->info->speed, finecosine[an]);
th->momy = FixedMul(th->info->speed, finesine[an]);
dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
dist = dist / th->info->speed;
if (dist < 1)
dist = 1;
th->momz = (dest->z - source->z) / dist;
P_CheckMissileSpawn(th);
return th;
}
//
// P_SpawnPlayerMissile
// Tries to aim at a nearby monster
//
void P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type)
{
mobj_t* th;
angle_t an;
fixed_t x;
fixed_t y;
fixed_t z;
fixed_t slope;
// see which target is to be aimed at
an = source->angle;
slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT);
if (!linetarget)
{
an += 1 << 26;
slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT);
if (!linetarget)
{
an -= 2 << 26;
slope = P_AimLineAttack(source, an, 16 * 64 * FRACUNIT);
}
if (!linetarget)
{
an = source->angle;
slope = 0;
}
}
x = source->x;
y = source->y;
z = source->z + 4 * 8 * FRACUNIT;
th = P_SpawnMobj(x, y, z, type);
if (th->info->seesound)
S_StartSound(th, th->info->seesound);
th->target = source;
th->angle = an;
th->momx = FixedMul(th->info->speed,
finecosine[an >> ANGLETOFINESHIFT]);
th->momy = FixedMul(th->info->speed,
finesine[an >> ANGLETOFINESHIFT]);
th->momz = FixedMul(th->info->speed, slope);
P_CheckMissileSpawn(th);
}

286
src/DOOM/p_mobj.h Normal file
View File

@ -0,0 +1,286 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Map Objects, MObj, definition and handling.
//
//-----------------------------------------------------------------------------
#ifndef __P_MOBJ__
#define __P_MOBJ__
// Basics.
#include "tables.h"
#include "m_fixed.h"
// We need the thinker_t stuff.
#include "d_think.h"
// We need the WAD data structure for Map things,
// from the THINGS lump.
#include "doomdata.h"
// States are tied to finite states are
// tied to animation frames.
// Needs precompiled tables/data structures.
#include "info.h"
//
// NOTES: mobj_t
//
// mobj_ts are used to tell the refresh where to draw an image,
// tell the world simulation when objects are contacted,
// and tell the sound driver how to position a sound.
//
// The refresh uses the next and prev links to follow
// lists of things in sectors as they are being drawn.
// The sprite, frame, and angle elements determine which patch_t
// is used to draw the sprite if it is visible.
// The sprite and frame values are allmost allways set
// from state_t structures.
// The statescr.exe utility generates the states.h and states.c
// files that contain the sprite/frame numbers from the
// statescr.txt source file.
// The xyz origin point represents a point at the bottom middle
// of the sprite (between the feet of a biped).
// This is the default origin position for patch_ts grabbed
// with lumpy.exe.
// A walking creature will have its z equal to the floor
// it is standing on.
//
// The sound code uses the x,y, and subsector fields
// to do stereo positioning of any sound effited by the mobj_t.
//
// The play simulation uses the blocklinks, x,y,z, radius, height
// to determine when mobj_ts are touching each other,
// touching lines in the map, or hit by trace lines (gunshots,
// lines of sight, etc).
// The mobj_t->flags element has various bit flags
// used by the simulation.
//
// Every mobj_t is linked into a single sector
// based on its origin coordinates.
// The subsector_t is found with R_PointInSubsector(x,y),
// and the sector_t can be found with subsector->sector.
// The sector links are only used by the rendering code,
// the play simulation does not care about them at all.
//
// Any mobj_t that needs to be acted upon by something else
// in the play world (block movement, be shot, etc) will also
// need to be linked into the blockmap.
// If the thing has the MF_NOBLOCK flag set, it will not use
// the block links. It can still interact with other things,
// but only as the instigator (missiles will run into other
// things, but nothing can run into a missile).
// Each block in the grid is 128*128 units, and knows about
// every line_t that it contains a piece of, and every
// interactable mobj_t that has its origin contained.
//
// A valid mobj_t is a mobj_t that has the proper subsector_t
// filled in for its xy coordinates and is linked into the
// sector from which the subsector was made, or has the
// MF_NOSECTOR flag set (the subsector_t needs to be valid
// even if MF_NOSECTOR is set), and is linked into a blockmap
// block or has the MF_NOBLOCKMAP flag set.
// Links should only be modified by the P_[Un]SetThingPosition()
// functions.
// Do not change the MF_NO? flags while a thing is valid.
//
// Any questions?
//
//
// Misc. mobj flags
//
typedef enum
{
// Call P_SpecialThing when touched.
MF_SPECIAL = 1,
// Blocks.
MF_SOLID = 2,
// Can be hit.
MF_SHOOTABLE = 4,
// Don't use the sector links (invisible but touchable).
MF_NOSECTOR = 8,
// Don't use the blocklinks (inert but displayable)
MF_NOBLOCKMAP = 16,
// Not to be activated by sound, deaf monster.
MF_AMBUSH = 32,
// Will try to attack right back.
MF_JUSTHIT = 64,
// Will take at least one step before attacking.
MF_JUSTATTACKED = 128,
// On level spawning (initial position),
// hang from ceiling instead of stand on floor.
MF_SPAWNCEILING = 256,
// Don't apply gravity (every tic),
// that is, object will float, keeping current height
// or changing it actively.
MF_NOGRAVITY = 512,
// Movement flags.
// This allows jumps from high places.
MF_DROPOFF = 0x400,
// For players, will pick up items.
MF_PICKUP = 0x800,
// Player cheat. ???
MF_NOCLIP = 0x1000,
// Player: keep info about sliding along walls.
MF_SLIDE = 0x2000,
// Allow moves to any height, no gravity.
// For active floaters, e.g. cacodemons, pain elementals.
MF_FLOAT = 0x4000,
// Don't cross lines
// ??? or look at heights on teleport.
MF_TELEPORT = 0x8000,
// Don't hit same species, explode on block.
// Player missiles as well as fireballs of various kinds.
MF_MISSILE = 0x10000,
// Dropped by a demon, not level spawned.
// E.g. ammo clips dropped by dying former humans.
MF_DROPPED = 0x20000,
// Use fuzzy draw (shadow demons or spectres),
// temporary player invisibility powerup.
MF_SHADOW = 0x40000,
// Flag: don't bleed when shot (use puff),
// barrels and shootable furniture shall not bleed.
MF_NOBLOOD = 0x80000,
// Don't stop moving halfway off a step,
// that is, have dead bodies slide down all the way.
MF_CORPSE = 0x100000,
// Floating to a height for a move, ???
// don't auto float to target's height.
MF_INFLOAT = 0x200000,
// On kill, count this enemy object
// towards intermission kill total.
// Happy gathering.
MF_COUNTKILL = 0x400000,
// On picking up, count this item object
// towards intermission item total.
MF_COUNTITEM = 0x800000,
// Special handling: skull in flight.
// Neither a cacodemon nor a missile.
MF_SKULLFLY = 0x1000000,
// Don't spawn this object
// in death match mode (e.g. key cards).
MF_NOTDMATCH = 0x2000000,
// Player sprites in multiplayer modes are modified
// using an internal color lookup table for re-indexing.
// If 0x4 0x8 or 0xc,
// use a translation table for player colormaps
MF_TRANSLATION = 0xc000000,
// Hmm ???.
MF_TRANSSHIFT = 26
} mobjflag_t;
// Map Object definition.
typedef struct mobj_s
{
// List: thinker links.
thinker_t thinker;
// Info for drawing: position.
fixed_t x;
fixed_t y;
fixed_t z;
// More list: links in sector (if needed)
struct mobj_s* snext;
struct mobj_s* sprev;
//More drawing info: to determine current sprite.
angle_t angle; // orientation
spritenum_t sprite; // used to find patch_t and flip value
int frame; // might be ORed with FF_FULLBRIGHT
// Interaction info, by BLOCKMAP.
// Links in blocks (if needed).
struct mobj_s* bnext;
struct mobj_s* bprev;
struct subsector_s* subsector;
// The closest interval over all contacted Sectors.
fixed_t floorz;
fixed_t ceilingz;
// For movement checking.
fixed_t radius;
fixed_t height;
// Momentums, used to update position.
fixed_t momx;
fixed_t momy;
fixed_t momz;
// If == validcount, already checked.
int validcount;
mobjtype_t type;
mobjinfo_t* info; // &mobjinfo[mobj->type]
int tics; // state tic counter
state_t* state;
int flags;
int health;
// Movement direction, movement generation (zig-zagging).
int movedir; // 0-7
int movecount; // when 0, select a new dir
// Thing being chased/attacked (or 0),
// also the originator for missiles.
struct mobj_s* target;
// Reaction time: if non 0, don't attack yet.
// Used by player to freeze a bit after teleporting.
int reactiontime;
// If >0, the target will be chased
// no matter what (even if shot)
int threshold;
// Additional info record for player avatars only.
// Only valid if type == MT_PLAYER
struct player_s* player;
// Player number last looked for.
int lastlook;
// For nightmare respawn.
mapthing_t spawnpoint;
// Thing being chased/attacked for tracers.
struct mobj_s* tracer;
} mobj_t;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

298
src/DOOM/p_plats.c Normal file
View File

@ -0,0 +1,298 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Plats (i.e. elevator platforms) code, raising/lowering.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "i_system.h"
#include "z_zone.h"
#include "m_random.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
#include "doomstat.h" // State.
#include "r_state.h" // State.
#include "sounds.h" // Data.
plat_t* activeplats[MAXPLATS];
//
// Move a plat up and down
//
void T_PlatRaise(plat_t* plat)
{
result_e res;
switch (plat->status)
{
case up:
res = T_MovePlane(plat->sector,
plat->speed,
plat->high,
plat->crush, 0, 1);
if (plat->type == raiseAndChange
|| plat->type == raiseToNearestAndChange)
{
if (!(leveltime & 7))
S_StartSound((mobj_t*)&plat->sector->soundorg,
sfx_stnmov);
}
if (res == crushed && (!plat->crush))
{
plat->count = plat->wait;
plat->status = down;
S_StartSound((mobj_t*)&plat->sector->soundorg,
sfx_pstart);
}
else
{
if (res == pastdest)
{
plat->count = plat->wait;
plat->status = waiting;
S_StartSound((mobj_t*)&plat->sector->soundorg,
sfx_pstop);
switch (plat->type)
{
case blazeDWUS:
case downWaitUpStay:
P_RemoveActivePlat(plat);
break;
case raiseAndChange:
case raiseToNearestAndChange:
P_RemoveActivePlat(plat);
break;
default:
break;
}
}
}
break;
case down:
res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1);
if (res == pastdest)
{
plat->count = plat->wait;
plat->status = waiting;
S_StartSound((mobj_t*)&plat->sector->soundorg, sfx_pstop);
}
break;
case waiting:
if (!--plat->count)
{
if (plat->sector->floorheight == plat->low)
plat->status = up;
else
plat->status = down;
S_StartSound((mobj_t*)&plat->sector->soundorg, sfx_pstart);
}
case in_stasis:
break;
}
}
//
// Do Platforms
// "amount" is only used for SOME platforms.
//
int EV_DoPlat(line_t* line, plattype_e type, int amount)
{
plat_t* plat;
int secnum;
int rtn;
sector_t* sec;
secnum = -1;
rtn = 0;
// Activate all <type> plats that are in_stasis
switch (type)
{
case perpetualRaise:
P_ActivateInStasis(line->tag);
break;
default:
break;
}
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
// Find lowest & highest floors around sector
rtn = 1;
plat = Z_Malloc(sizeof(*plat), PU_LEVSPEC, 0);
P_AddThinker(&plat->thinker);
plat->type = type;
plat->sector = sec;
plat->sector->specialdata = plat;
plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise;
plat->crush = false;
plat->tag = line->tag;
switch (type)
{
case raiseToNearestAndChange:
plat->speed = PLATSPEED / 2;
sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
plat->high = P_FindNextHighestFloor(sec, sec->floorheight);
plat->wait = 0;
plat->status = up;
// NO MORE DAMAGE, IF APPLICABLE
sec->special = 0;
S_StartSound((mobj_t*)&sec->soundorg, sfx_stnmov);
break;
case raiseAndChange:
plat->speed = PLATSPEED / 2;
sec->floorpic = sides[line->sidenum[0]].sector->floorpic;
plat->high = sec->floorheight + amount * FRACUNIT;
plat->wait = 0;
plat->status = up;
S_StartSound((mobj_t*)&sec->soundorg, sfx_stnmov);
break;
case downWaitUpStay:
plat->speed = PLATSPEED * 4;
plat->low = P_FindLowestFloorSurrounding(sec);
if (plat->low > sec->floorheight)
plat->low = sec->floorheight;
plat->high = sec->floorheight;
plat->wait = 35 * PLATWAIT;
plat->status = down;
S_StartSound((mobj_t*)&sec->soundorg, sfx_pstart);
break;
case blazeDWUS:
plat->speed = PLATSPEED * 8;
plat->low = P_FindLowestFloorSurrounding(sec);
if (plat->low > sec->floorheight)
plat->low = sec->floorheight;
plat->high = sec->floorheight;
plat->wait = 35 * PLATWAIT;
plat->status = down;
S_StartSound((mobj_t*)&sec->soundorg, sfx_pstart);
break;
case perpetualRaise:
plat->speed = PLATSPEED;
plat->low = P_FindLowestFloorSurrounding(sec);
if (plat->low > sec->floorheight)
plat->low = sec->floorheight;
plat->high = P_FindHighestFloorSurrounding(sec);
if (plat->high < sec->floorheight)
plat->high = sec->floorheight;
plat->wait = 35 * PLATWAIT;
plat->status = P_Random() & 1;
S_StartSound((mobj_t*)&sec->soundorg, sfx_pstart);
break;
}
P_AddActivePlat(plat);
}
return rtn;
}
void P_ActivateInStasis(int tag)
{
int i;
for (i = 0; i < MAXPLATS; i++)
if (activeplats[i]
&& (activeplats[i])->tag == tag
&& (activeplats[i])->status == in_stasis)
{
(activeplats[i])->status = (activeplats[i])->oldstatus;
(activeplats[i])->thinker.function.acp1 = (actionf_p1)T_PlatRaise;
}
}
void EV_StopPlat(line_t* line)
{
int j;
for (j = 0; j < MAXPLATS; j++)
if (activeplats[j]
&& ((activeplats[j])->status != in_stasis)
&& ((activeplats[j])->tag == line->tag))
{
(activeplats[j])->oldstatus = (activeplats[j])->status;
(activeplats[j])->status = in_stasis;
(activeplats[j])->thinker.function.acv = (actionf_v)0;
}
}
void P_AddActivePlat(plat_t* plat)
{
int i;
for (i = 0; i < MAXPLATS; i++)
if (activeplats[i] == 0)
{
activeplats[i] = plat;
return;
}
I_Error("Error: P_AddActivePlat: no more plats!");
}
void P_RemoveActivePlat(plat_t* plat)
{
int i;
for (i = 0; i < MAXPLATS; i++)
if (plat == activeplats[i])
{
(activeplats[i])->sector->specialdata = 0;
P_RemoveThinker(&(activeplats[i])->thinker);
activeplats[i] = 0;
return;
}
I_Error("Error: P_RemoveActivePlat: can't find plat!");
}

778
src/DOOM/p_pspr.c Normal file
View File

@ -0,0 +1,778 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Weapon sprite animation, weapon objects.
// Action functions for weapons.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "d_event.h"
#include "m_random.h"
#include "p_local.h"
#include "s_sound.h"
#include "doomstat.h" // State.
#include "sounds.h" // Data.
#include "p_pspr.h"
#define LOWERSPEED (FRACUNIT*6)
#define RAISESPEED (FRACUNIT*6)
#define WEAPONBOTTOM (128*FRACUNIT)
#define WEAPONTOP (32*FRACUNIT)
// plasma cells for a bfg attack
#define BFGCELLS 40
fixed_t swingx;
fixed_t swingy;
fixed_t bulletslope;
//
// P_SetPsprite
//
void P_SetPsprite(player_t* player, int position, statenum_t stnum)
{
pspdef_t* psp;
state_t* state;
psp = &player->psprites[position];
do
{
if (!stnum)
{
// object removed itself
psp->state = 0;
break;
}
state = &states[stnum];
psp->state = state;
psp->tics = state->tics; // could be 0
if (state->misc1)
{
// coordinate set
psp->sx = state->misc1 << FRACBITS;
psp->sy = state->misc2 << FRACBITS;
}
// Call action routine.
// Modified handling.
if (state->action.acp2)
{
state->action.acp2(player, psp);
if (!psp->state)
break;
}
stnum = psp->state->nextstate;
} while (!psp->tics);
// an initial state of 0 could cycle through
}
//
// P_BringUpWeapon
// Starts bringing the pending weapon up
// from the bottom of the screen.
// Uses player
//
void P_BringUpWeapon(player_t* player)
{
statenum_t newstate;
if (player->pendingweapon == wp_nochange)
player->pendingweapon = player->readyweapon;
if (player->pendingweapon == wp_chainsaw)
S_StartSound(player->mo, sfx_sawup);
newstate = weaponinfo[player->pendingweapon].upstate;
player->pendingweapon = wp_nochange;
player->psprites[ps_weapon].sy = WEAPONBOTTOM;
P_SetPsprite(player, ps_weapon, newstate);
}
//
// P_CheckAmmo
// Returns true if there is enough ammo to shoot.
// If not, selects the next weapon to use.
//
doom_boolean P_CheckAmmo(player_t* player)
{
ammotype_t ammo;
int count;
ammo = weaponinfo[player->readyweapon].ammo;
// Minimal amount for one shot varies.
if (player->readyweapon == wp_bfg)
count = BFGCELLS;
else if (player->readyweapon == wp_supershotgun)
count = 2; // Double barrel.
else
count = 1; // Regular.
// Some do not need ammunition anyway.
// Return if current ammunition sufficient.
if (ammo == am_noammo || player->ammo[ammo] >= count)
return true;
// Out of ammo, pick a weapon to change to.
// Preferences are set here.
do
{
if (player->weaponowned[wp_plasma]
&& player->ammo[am_cell]
&& (gamemode != shareware))
{
player->pendingweapon = wp_plasma;
}
else if (player->weaponowned[wp_supershotgun]
&& player->ammo[am_shell] > 2
&& (gamemode == commercial))
{
player->pendingweapon = wp_supershotgun;
}
else if (player->weaponowned[wp_chaingun]
&& player->ammo[am_clip])
{
player->pendingweapon = wp_chaingun;
}
else if (player->weaponowned[wp_shotgun]
&& player->ammo[am_shell])
{
player->pendingweapon = wp_shotgun;
}
else if (player->ammo[am_clip])
{
player->pendingweapon = wp_pistol;
}
else if (player->weaponowned[wp_chainsaw])
{
player->pendingweapon = wp_chainsaw;
}
else if (player->weaponowned[wp_missile]
&& player->ammo[am_misl])
{
player->pendingweapon = wp_missile;
}
else if (player->weaponowned[wp_bfg]
&& player->ammo[am_cell] > 40
&& (gamemode != shareware))
{
player->pendingweapon = wp_bfg;
}
else
{
// If everything fails.
player->pendingweapon = wp_fist;
}
} while (player->pendingweapon == wp_nochange);
// Now set appropriate weapon overlay.
P_SetPsprite(player,
ps_weapon,
weaponinfo[player->readyweapon].downstate);
return false;
}
//
// P_FireWeapon.
//
void P_FireWeapon(player_t* player)
{
statenum_t newstate;
if (!P_CheckAmmo(player))
return;
P_SetMobjState(player->mo, S_PLAY_ATK1);
newstate = weaponinfo[player->readyweapon].atkstate;
P_SetPsprite(player, ps_weapon, newstate);
P_NoiseAlert(player->mo, player->mo);
// [pd] Stop gun bobbing when shooting
pspdef_t* psp;
psp = &player->psprites[ps_weapon];
psp->sx = FRACUNIT;
psp->sy = WEAPONTOP;
}
//
// P_DropWeapon
// Player died, so put the weapon away.
//
void P_DropWeapon(player_t* player)
{
P_SetPsprite(player,
ps_weapon,
weaponinfo[player->readyweapon].downstate);
}
//
// A_WeaponReady
// The player can fire the weapon
// or change to another weapon at this time.
// Follows after getting weapon up,
// or after previous attack/fire sequence.
//
void A_WeaponReady(player_t* player, pspdef_t* psp)
{
statenum_t newstate;
int angle;
// get out of attack state
if (player->mo->state == &states[S_PLAY_ATK1]
|| player->mo->state == &states[S_PLAY_ATK2])
{
P_SetMobjState(player->mo, S_PLAY);
}
if (player->readyweapon == wp_chainsaw
&& psp->state == &states[S_SAW])
{
S_StartSound(player->mo, sfx_sawidl);
}
// check for change
// if player is dead, put the weapon away
if (player->pendingweapon != wp_nochange || !player->health)
{
// change weapon
// (pending weapon should allready be validated)
newstate = weaponinfo[player->readyweapon].downstate;
P_SetPsprite(player, ps_weapon, newstate);
return;
}
// check for fire
// the missile launcher and bfg do not auto fire
if (player->cmd.buttons & BT_ATTACK)
{
if (!player->attackdown
|| (player->readyweapon != wp_missile
&& player->readyweapon != wp_bfg))
{
player->attackdown = true;
P_FireWeapon(player);
return;
}
}
else
player->attackdown = false;
// bob the weapon based on movement speed
angle = (128 * leveltime) & FINEMASK;
psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
angle &= FINEANGLES / 2 - 1;
psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
}
//
// A_ReFire
// The player can re-fire the weapon
// without lowering it entirely.
//
void A_ReFire(player_t* player, pspdef_t* psp)
{
// check for fire
// (if a weaponchange is pending, let it go through instead)
if ((player->cmd.buttons & BT_ATTACK)
&& player->pendingweapon == wp_nochange
&& player->health)
{
player->refire++;
P_FireWeapon(player);
}
else
{
player->refire = 0;
P_CheckAmmo(player);
}
}
void A_CheckReload(player_t* player, pspdef_t* psp)
{
P_CheckAmmo(player);
}
//
// A_Lower
// Lowers current weapon,
// and changes weapon at bottom.
//
void A_Lower(player_t* player, pspdef_t* psp)
{
psp->sy += LOWERSPEED;
// Is already down.
if (psp->sy < WEAPONBOTTOM)
return;
// Player is dead.
if (player->playerstate == PST_DEAD)
{
psp->sy = WEAPONBOTTOM;
// don't bring weapon back up
return;
}
// The old weapon has been lowered off the screen,
// so change the weapon and start raising it
if (!player->health)
{
// Player is dead, so keep the weapon off screen.
P_SetPsprite(player, ps_weapon, S_NULL);
return;
}
player->readyweapon = player->pendingweapon;
P_BringUpWeapon(player);
}
//
// A_Raise
//
void A_Raise(player_t* player, pspdef_t* psp)
{
statenum_t newstate;
psp->sy -= RAISESPEED;
if (psp->sy > WEAPONTOP)
return;
psp->sy = WEAPONTOP;
// The weapon has been raised all the way,
// so change to the ready state.
newstate = weaponinfo[player->readyweapon].readystate;
P_SetPsprite(player, ps_weapon, newstate);
}
//
// A_GunFlash
//
void A_GunFlash(player_t* player, pspdef_t* psp)
{
P_SetMobjState(player->mo, S_PLAY_ATK2);
P_SetPsprite(player, ps_flash, weaponinfo[player->readyweapon].flashstate);
}
//
// WEAPON ATTACKS
//
//
// A_Punch
//
void A_Punch(player_t* player, pspdef_t* psp)
{
angle_t angle;
int damage;
int slope;
damage = (P_Random() % 10 + 1) << 1;
if (player->powers[pw_strength])
damage *= 10;
angle = player->mo->angle;
angle += (P_Random() - P_Random()) << 18;
slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
// turn to face target
if (linetarget)
{
S_StartSound(player->mo, sfx_punch);
player->mo->angle = R_PointToAngle2(player->mo->x,
player->mo->y,
linetarget->x,
linetarget->y);
}
}
//
// A_Saw
//
void A_Saw(player_t* player, pspdef_t* psp)
{
angle_t angle;
int damage;
int slope;
damage = 2 * (P_Random() % 10 + 1);
angle = player->mo->angle;
angle += (P_Random() - P_Random()) << 18;
// use meleerange + 1 se the puff doesn't skip the flash
slope = P_AimLineAttack(player->mo, angle, MELEERANGE + 1);
P_LineAttack(player->mo, angle, MELEERANGE + 1, slope, damage);
if (!linetarget)
{
S_StartSound(player->mo, sfx_sawful);
return;
}
S_StartSound(player->mo, sfx_sawhit);
// turn to face target
angle = R_PointToAngle2(player->mo->x, player->mo->y,
linetarget->x, linetarget->y);
if (angle - player->mo->angle > ANG180)
{
if (angle - player->mo->angle < -ANG90 / 20)
player->mo->angle = angle + ANG90 / 21;
else
player->mo->angle -= ANG90 / 20;
}
else
{
if (angle - player->mo->angle > ANG90 / 20)
player->mo->angle = angle - ANG90 / 21;
else
player->mo->angle += ANG90 / 20;
}
player->mo->flags |= MF_JUSTATTACKED;
}
//
// A_FireMissile
//
void A_FireMissile(player_t* player, pspdef_t* psp)
{
player->ammo[weaponinfo[player->readyweapon].ammo]--;
P_SpawnPlayerMissile(player->mo, MT_ROCKET);
}
//
// A_FireBFG
//
void A_FireBFG(player_t* player, pspdef_t* psp)
{
player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
P_SpawnPlayerMissile(player->mo, MT_BFG);
}
//
// A_FirePlasma
//
void A_FirePlasma(player_t* player, pspdef_t* psp)
{
player->ammo[weaponinfo[player->readyweapon].ammo]--;
P_SetPsprite(player,
ps_flash,
weaponinfo[player->readyweapon].flashstate + (P_Random() & 1));
P_SpawnPlayerMissile(player->mo, MT_PLASMA);
}
//
// P_BulletSlope
// Sets a slope so a near miss is at aproximately
// the height of the intended target
//
void P_BulletSlope(mobj_t* mo)
{
angle_t an;
// see which target is to be aimed at
an = mo->angle;
bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
if (!linetarget)
{
an += 1 << 26;
bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
if (!linetarget)
{
an -= 2 << 26;
bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
}
}
}
//
// P_GunShot
//
void P_GunShot(mobj_t* mo, doom_boolean accurate)
{
angle_t angle;
int damage;
damage = 5 * (P_Random() % 3 + 1);
angle = mo->angle;
if (!accurate)
angle += (P_Random() - P_Random()) << 18;
P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
}
//
// A_FirePistol
//
void A_FirePistol(player_t* player, pspdef_t* psp)
{
S_StartSound(player->mo, sfx_pistol);
P_SetMobjState(player->mo, S_PLAY_ATK2);
player->ammo[weaponinfo[player->readyweapon].ammo]--;
P_SetPsprite(player,
ps_flash,
weaponinfo[player->readyweapon].flashstate);
P_BulletSlope(player->mo);
P_GunShot(player->mo, !player->refire);
}
//
// A_FireShotgun
//
void A_FireShotgun(player_t* player, pspdef_t* psp)
{
int i;
S_StartSound(player->mo, sfx_shotgn);
P_SetMobjState(player->mo, S_PLAY_ATK2);
player->ammo[weaponinfo[player->readyweapon].ammo]--;
P_SetPsprite(player,
ps_flash,
weaponinfo[player->readyweapon].flashstate);
P_BulletSlope(player->mo);
for (i = 0; i < 7; i++)
P_GunShot(player->mo, false);
}
//
// A_FireShotgun2
//
void A_FireShotgun2(player_t* player, pspdef_t* psp)
{
int i;
angle_t angle;
int damage;
S_StartSound(player->mo, sfx_dshtgn);
P_SetMobjState(player->mo, S_PLAY_ATK2);
player->ammo[weaponinfo[player->readyweapon].ammo] -= 2;
P_SetPsprite(player,
ps_flash,
weaponinfo[player->readyweapon].flashstate);
P_BulletSlope(player->mo);
for (i = 0; i < 20; i++)
{
damage = 5 * (P_Random() % 3 + 1);
angle = player->mo->angle;
angle += (P_Random() - P_Random()) << 19;
P_LineAttack(player->mo,
angle,
MISSILERANGE,
bulletslope + ((P_Random() - P_Random()) << 5), damage);
}
}
//
// A_FireCGun
//
void A_FireCGun(player_t* player, pspdef_t* psp)
{
S_StartSound(player->mo, sfx_pistol);
if (!player->ammo[weaponinfo[player->readyweapon].ammo])
return;
P_SetMobjState(player->mo, S_PLAY_ATK2);
player->ammo[weaponinfo[player->readyweapon].ammo]--;
P_SetPsprite(player,
ps_flash,
weaponinfo[player->readyweapon].flashstate
+ psp->state
- &states[S_CHAIN1]);
P_BulletSlope(player->mo);
P_GunShot(player->mo, !player->refire);
}
//
// ?
//
void A_Light0(player_t* player, pspdef_t* psp)
{
player->extralight = 0;
}
void A_Light1(player_t* player, pspdef_t* psp)
{
player->extralight = 1;
}
void A_Light2(player_t* player, pspdef_t* psp)
{
player->extralight = 2;
}
//
// A_BFGSpray
// Spawn a BFG explosion on every monster in view
//
void A_BFGSpray(mobj_t* mo)
{
int i;
int j;
int damage;
angle_t an;
// offset angles from its attack angle
for (i = 0; i < 40; i++)
{
an = mo->angle - ANG90 / 2 + ANG90 / 40 * i;
// mo->target is the originator (player)
// of the missile
P_AimLineAttack(mo->target, an, 16 * 64 * FRACUNIT);
if (!linetarget)
continue;
P_SpawnMobj(linetarget->x,
linetarget->y,
linetarget->z + (linetarget->height >> 2),
MT_EXTRABFG);
damage = 0;
for (j = 0; j < 15; j++)
damage += (P_Random() & 7) + 1;
P_DamageMobj(linetarget, mo->target, mo->target, damage);
}
}
//
// A_BFGsound
//
void A_BFGsound(player_t* player, pspdef_t* psp)
{
S_StartSound(player->mo, sfx_bfg);
}
//
// P_SetupPsprites
// Called at start of level for each player.
//
void P_SetupPsprites(player_t* player)
{
int i;
// remove all psprites
for (i = 0; i < NUMPSPRITES; i++)
player->psprites[i].state = 0;
// spawn the gun
player->pendingweapon = player->readyweapon;
P_BringUpWeapon(player);
}
//
// P_MovePsprites
// Called every tic by player thinking routine.
//
void P_MovePsprites(player_t* player)
{
int i;
pspdef_t* psp;
state_t* state;
psp = &player->psprites[0];
for (i = 0; i < NUMPSPRITES; i++, psp++)
{
// a null state means not active
if ((state = psp->state))
{
// drop tic count and possibly change state
// a -1 tic count never changes
if (psp->tics != -1)
{
psp->tics--;
if (!psp->tics)
P_SetPsprite(player, i, psp->state->nextstate);
}
}
}
player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
}

75
src/DOOM/p_pspr.h Normal file
View File

@ -0,0 +1,75 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Sprite animation.
//
//-----------------------------------------------------------------------------
#ifndef __P_PSPR__
#define __P_PSPR__
// Basic data types.
// Needs fixed point, and BAM angles.
#include "m_fixed.h"
#include "tables.h"
// Needs to include the precompiled
// sprite animation tables.
// Header generated by multigen utility.
// This includes all the data for thing animation,
// i.e. the Thing Atrributes table
// and the Frame Sequence table.
#include "info.h"
//
// Frame flags:
// handles maximum brightness (torches, muzzle flare, light sources)
//
#define FF_FULLBRIGHT 0x8000 // flag in thing->frame
#define FF_FRAMEMASK 0x7fff
//
// Overlay psprites are scaled shapes
// drawn directly on the view screen,
// coordinates are given for a 320*200 view screen.
//
typedef enum
{
ps_weapon,
ps_flash,
NUMPSPRITES
} psprnum_t;
typedef struct
{
state_t* state; // a 0 state means not active
int tics;
fixed_t sx;
fixed_t sy;
} pspdef_t;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

584
src/DOOM/p_saveg.c Normal file
View File

@ -0,0 +1,584 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Archiving: SaveGame I/O.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "i_system.h"
#include "z_zone.h"
#include "p_local.h"
#include "doomstat.h" // State.
#include "r_state.h" // State.
// Pads save_p to a 4-byte boundary
// so that the load/save works on SGI&Gecko.
#define PADSAVEP() save_p += (4 - ((long long)save_p & 3)) & 3
byte* save_p;
// TODO: [pd] We are loading/saving raw pointers. It will not work with saves from 32bits system. We need to rewrite those functions.
//
// P_ArchivePlayers
//
void P_ArchivePlayers(void)
{
int i;
int j;
player_t* dest;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
PADSAVEP();
dest = (player_t*)save_p;
doom_memcpy(dest, &players[i], sizeof(player_t));
save_p += sizeof(player_t);
for (j = 0; j < NUMPSPRITES; j++)
{
if (dest->psprites[j].state)
{
dest->psprites[j].state
= (state_t*)(dest->psprites[j].state - states);
}
}
}
}
//
// P_UnArchivePlayers
//
void P_UnArchivePlayers(void)
{
int i;
int j;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
PADSAVEP();
doom_memcpy(&players[i], save_p, sizeof(player_t));
save_p += sizeof(player_t);
// will be set when unarc thinker
players[i].mo = 0;
players[i].message = 0;
players[i].attacker = 0;
for (j = 0; j < NUMPSPRITES; j++)
{
if (players[i].psprites[j].state)
{
players[i].psprites[j].state
= &states[(long long)players[i].psprites[j].state];
}
}
}
}
//
// P_ArchiveWorld
//
void P_ArchiveWorld(void)
{
int i;
int j;
sector_t* sec;
line_t* li;
side_t* si;
short* put;
put = (short*)save_p;
// do sectors
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
{
*put++ = sec->floorheight >> FRACBITS;
*put++ = sec->ceilingheight >> FRACBITS;
*put++ = sec->floorpic;
*put++ = sec->ceilingpic;
*put++ = sec->lightlevel;
*put++ = sec->special; // needed?
*put++ = sec->tag; // needed?
}
// do lines
for (i = 0, li = lines; i < numlines; i++, li++)
{
*put++ = li->flags;
*put++ = li->special;
*put++ = li->tag;
for (j = 0; j < 2; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &sides[li->sidenum[j]];
*put++ = si->textureoffset >> FRACBITS;
*put++ = si->rowoffset >> FRACBITS;
*put++ = si->toptexture;
*put++ = si->bottomtexture;
*put++ = si->midtexture;
}
}
save_p = (byte*)put;
}
//
// P_UnArchiveWorld
//
void P_UnArchiveWorld(void)
{
int i;
int j;
sector_t* sec;
line_t* li;
side_t* si;
short* get;
get = (short*)save_p;
// do sectors
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
{
sec->floorheight = *get++ << FRACBITS;
sec->ceilingheight = *get++ << FRACBITS;
sec->floorpic = *get++;
sec->ceilingpic = *get++;
sec->lightlevel = *get++;
sec->special = *get++; // needed?
sec->tag = *get++; // needed?
sec->specialdata = 0;
sec->soundtarget = 0;
}
// do lines
for (i = 0, li = lines; i < numlines; i++, li++)
{
li->flags = *get++;
li->special = *get++;
li->tag = *get++;
for (j = 0; j < 2; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &sides[li->sidenum[j]];
si->textureoffset = *get++ << FRACBITS;
si->rowoffset = *get++ << FRACBITS;
si->toptexture = *get++;
si->bottomtexture = *get++;
si->midtexture = *get++;
}
}
save_p = (byte*)get;
}
//
// Thinkers
//
typedef enum
{
tc_end,
tc_mobj
} thinkerclass_t;
//
// P_ArchiveThinkers
//
void P_ArchiveThinkers(void)
{
thinker_t* th;
mobj_t* mobj;
// save off the current thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
{
*save_p++ = tc_mobj;
PADSAVEP();
mobj = (mobj_t*)save_p;
doom_memcpy(mobj, th, sizeof(*mobj));
save_p += sizeof(*mobj);
mobj->state = (state_t*)(mobj->state - states);
if (mobj->player)
mobj->player = (player_t*)((mobj->player - players) + 1);
continue;
}
// I_Error ("P_ArchiveThinkers: Unknown thinker function");
}
// add a terminating marker
*save_p++ = tc_end;
}
//
// P_UnArchiveThinkers
//
void P_UnArchiveThinkers(void)
{
byte tclass;
thinker_t* currentthinker;
thinker_t* next;
mobj_t* mobj;
// remove all the current thinkers
currentthinker = thinkercap.next;
while (currentthinker != &thinkercap)
{
next = currentthinker->next;
if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
P_RemoveMobj((mobj_t*)currentthinker);
else
Z_Free(currentthinker);
currentthinker = next;
}
P_InitThinkers();
// read in saved thinkers
while (1)
{
tclass = *save_p++;
switch (tclass)
{
case tc_end:
return; // end of list
case tc_mobj:
PADSAVEP();
mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, 0);
doom_memcpy(mobj, save_p, sizeof(*mobj));
save_p += sizeof(*mobj);
mobj->state = &states[(long long)mobj->state];
mobj->target = 0;
if (mobj->player)
{
mobj->player = &players[(long long)mobj->player - 1];
mobj->player->mo = mobj;
}
P_SetThingPosition(mobj);
mobj->info = &mobjinfo[mobj->type];
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
P_AddThinker(&mobj->thinker);
break;
default:
{
//I_Error("Error: Unknown tclass %i in savegame", tclass);
doom_strcpy(error_buf, "Error: Unknown tclass ");
doom_concat(error_buf, doom_itoa(tclass, 10));
doom_concat(error_buf, " in savegame");
I_Error(error_buf);
}
}
}
}
//
// P_ArchiveSpecials
//
enum
{
tc_ceiling,
tc_door,
tc_floor,
tc_plat,
tc_flash,
tc_strobe,
tc_glow,
tc_endspecials
} specials_e;
//
// Things to handle:
//
// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
// T_VerticalDoor, (vldoor_t: sector_t * swizzle),
// T_MoveFloor, (floormove_t: sector_t * swizzle),
// T_LightFlash, (lightflash_t: sector_t * swizzle),
// T_StrobeFlash, (strobe_t: sector_t *),
// T_Glow, (glow_t: sector_t *),
// T_PlatRaise, (plat_t: sector_t *), - active list
//
void P_ArchiveSpecials(void)
{
thinker_t* th;
ceiling_t* ceiling;
vldoor_t* door;
floormove_t* floor;
plat_t* plat;
lightflash_t* flash;
strobe_t* strobe;
glow_t* glow;
int i;
// save off the current thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acv == (actionf_v)0)
{
for (i = 0; i < MAXCEILINGS; i++)
if (activeceilings[i] == (ceiling_t*)th)
break;
if (i < MAXCEILINGS)
{
*save_p++ = tc_ceiling;
PADSAVEP();
ceiling = (ceiling_t*)save_p;
doom_memcpy(ceiling, th, sizeof(*ceiling));
save_p += sizeof(*ceiling);
ceiling->sector = (sector_t*)(ceiling->sector - sectors);
}
continue;
}
if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
{
*save_p++ = tc_ceiling;
PADSAVEP();
ceiling = (ceiling_t*)save_p;
doom_memcpy(ceiling, th, sizeof(*ceiling));
save_p += sizeof(*ceiling);
ceiling->sector = (sector_t*)(ceiling->sector - sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
{
*save_p++ = tc_door;
PADSAVEP();
door = (vldoor_t*)save_p;
doom_memcpy(door, th, sizeof(*door));
save_p += sizeof(*door);
door->sector = (sector_t*)(door->sector - sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_MoveFloor)
{
*save_p++ = tc_floor;
PADSAVEP();
floor = (floormove_t*)save_p;
doom_memcpy(floor, th, sizeof(*floor));
save_p += sizeof(*floor);
floor->sector = (sector_t*)(floor->sector - sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_PlatRaise)
{
*save_p++ = tc_plat;
PADSAVEP();
plat = (plat_t*)save_p;
doom_memcpy(plat, th, sizeof(*plat));
save_p += sizeof(*plat);
plat->sector = (sector_t*)(plat->sector - sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_LightFlash)
{
*save_p++ = tc_flash;
PADSAVEP();
flash = (lightflash_t*)save_p;
doom_memcpy(flash, th, sizeof(*flash));
save_p += sizeof(*flash);
flash->sector = (sector_t*)(flash->sector - sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
{
*save_p++ = tc_strobe;
PADSAVEP();
strobe = (strobe_t*)save_p;
doom_memcpy(strobe, th, sizeof(*strobe));
save_p += sizeof(*strobe);
strobe->sector = (sector_t*)(strobe->sector - sectors);
continue;
}
if (th->function.acp1 == (actionf_p1)T_Glow)
{
*save_p++ = tc_glow;
PADSAVEP();
glow = (glow_t*)save_p;
doom_memcpy(glow, th, sizeof(*glow));
save_p += sizeof(*glow);
glow->sector = (sector_t*)(glow->sector - sectors);
continue;
}
}
// add a terminating marker
*save_p++ = tc_endspecials;
}
//
// P_UnArchiveSpecials
//
void P_UnArchiveSpecials(void)
{
byte tclass;
ceiling_t* ceiling;
vldoor_t* door;
floormove_t* floor;
plat_t* plat;
lightflash_t* flash;
strobe_t* strobe;
glow_t* glow;
// read in saved thinkers
while (1)
{
tclass = *save_p++;
switch (tclass)
{
case tc_endspecials:
return; // end of list
case tc_ceiling:
PADSAVEP();
ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVEL, 0);
doom_memcpy(ceiling, save_p, sizeof(*ceiling));
save_p += sizeof(*ceiling);
ceiling->sector = &sectors[(long long)ceiling->sector];
ceiling->sector->specialdata = ceiling;
if (ceiling->thinker.function.acp1)
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
P_AddThinker(&ceiling->thinker);
P_AddActiveCeiling(ceiling);
break;
case tc_door:
PADSAVEP();
door = Z_Malloc(sizeof(*door), PU_LEVEL, 0);
doom_memcpy(door, save_p, sizeof(*door));
save_p += sizeof(*door);
door->sector = &sectors[(long long)door->sector];
door->sector->specialdata = door;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
P_AddThinker(&door->thinker);
break;
case tc_floor:
PADSAVEP();
floor = Z_Malloc(sizeof(*floor), PU_LEVEL, 0);
doom_memcpy(floor, save_p, sizeof(*floor));
save_p += sizeof(*floor);
floor->sector = &sectors[(long long)floor->sector];
floor->sector->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
P_AddThinker(&floor->thinker);
break;
case tc_plat:
PADSAVEP();
plat = Z_Malloc(sizeof(*plat), PU_LEVEL, 0);
doom_memcpy(plat, save_p, sizeof(*plat));
save_p += sizeof(*plat);
plat->sector = &sectors[(long long)plat->sector];
plat->sector->specialdata = plat;
if (plat->thinker.function.acp1)
plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise;
P_AddThinker(&plat->thinker);
P_AddActivePlat(plat);
break;
case tc_flash:
PADSAVEP();
flash = Z_Malloc(sizeof(*flash), PU_LEVEL, 0);
doom_memcpy(flash, save_p, sizeof(*flash));
save_p += sizeof(*flash);
flash->sector = &sectors[(long long)flash->sector];
flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
P_AddThinker(&flash->thinker);
break;
case tc_strobe:
PADSAVEP();
strobe = Z_Malloc(sizeof(*strobe), PU_LEVEL, 0);
doom_memcpy(strobe, save_p, sizeof(*strobe));
save_p += sizeof(*strobe);
strobe->sector = &sectors[(long long)strobe->sector];
strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
P_AddThinker(&strobe->thinker);
break;
case tc_glow:
PADSAVEP();
glow = Z_Malloc(sizeof(*glow), PU_LEVEL, 0);
doom_memcpy(glow, save_p, sizeof(*glow));
save_p += sizeof(*glow);
glow->sector = &sectors[(long long)glow->sector];
glow->thinker.function.acp1 = (actionf_p1)T_Glow;
P_AddThinker(&glow->thinker);
break;
default:
{
//I_Error("Error: P_UnarchiveSpecials:Unknown tclass %i "
// "in savegame", tclass);
doom_strcpy(error_buf, "Error: P_UnarchiveSpecials:Unknown tclass ");
doom_concat(error_buf, doom_itoa(tclass, 10));
doom_concat(error_buf, " in savegame");
I_Error(error_buf);
}
}
}
}

49
src/DOOM/p_saveg.h Normal file
View File

@ -0,0 +1,49 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Savegame I/O, archiving, persistence.
//
//-----------------------------------------------------------------------------
#ifndef __P_SAVEG__
#define __P_SAVEG__
#include "doomtype.h"
// Persistent storage/archiving.
// These are the load / save game routines.
void P_ArchivePlayers(void);
void P_UnArchivePlayers(void);
void P_ArchiveWorld(void);
void P_UnArchiveWorld(void);
void P_ArchiveThinkers(void);
void P_UnArchiveThinkers(void);
void P_ArchiveSpecials(void);
void P_UnArchiveSpecials(void);
extern byte* save_p;
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

674
src/DOOM/p_setup.c Normal file
View File

@ -0,0 +1,674 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Do all the WAD I/O, get map description,
// set up initial state and misc. LUTs.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "m_swap.h"
#include "m_bbox.h"
#include "g_game.h"
#include "i_system.h"
#include "w_wad.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
#include "doomstat.h"
// Maintain single and multi player starting spots.
#define MAX_DEATHMATCH_STARTS 10
//
// MAP related Lookup tables.
// Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
//
int numvertexes;
vertex_t* vertexes;
int numsegs;
seg_t* segs;
int numsectors;
sector_t* sectors;
int numsubsectors;
subsector_t* subsectors;
int numnodes;
node_t* nodes;
int numlines;
line_t* lines;
int numsides;
side_t* sides;
// BLOCKMAP
// Created from axis aligned bounding box
// of the map, a rectangular array of
// blocks of size ...
// Used to speed up collision detection
// by spatial subdivision in 2D.
//
// Blockmap size.
int bmapwidth;
int bmapheight; // size in mapblocks
short* blockmap; // int for larger maps
// offsets in blockmap are from here
short* blockmaplump;
// origin of block map
fixed_t bmaporgx;
fixed_t bmaporgy;
// for thing chains
mobj_t** blocklinks;
// REJECT
// For fast sight rejection.
// Speeds up enemy AI by skipping detailed
// LineOf Sight calculation.
// Without special effect, this could be
// used as a PVS lookup as well.
//
byte* rejectmatrix;
mapthing_t deathmatchstarts[MAX_DEATHMATCH_STARTS];
mapthing_t* deathmatch_p;
mapthing_t playerstarts[MAXPLAYERS];
void P_SpawnMapThing(mapthing_t* mthing);
//
// P_LoadVertexes
//
void P_LoadVertexes(int lump)
{
byte* data;
int i;
mapvertex_t* ml;
vertex_t* li;
// Determine number of lumps:
// total lump length / vertex record length.
numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
// Allocate zone memory for buffer.
vertexes = Z_Malloc(numvertexes * sizeof(vertex_t), PU_LEVEL, 0);
// Load data into cache.
data = W_CacheLumpNum(lump, PU_STATIC);
ml = (mapvertex_t*)data;
li = vertexes;
// Copy and convert vertex coordinates,
// internal representation as fixed.
for (i = 0; i < numvertexes; i++, li++, ml++)
{
li->x = SHORT(ml->x) << FRACBITS;
li->y = SHORT(ml->y) << FRACBITS;
}
// Free buffer memory.
Z_Free(data);
}
//
// P_LoadSegs
//
void P_LoadSegs(int lump)
{
byte* data;
int i;
mapseg_t* ml;
seg_t* li;
line_t* ldef;
int linedef;
int side;
numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0);
doom_memset(segs, 0, numsegs * sizeof(seg_t));
data = W_CacheLumpNum(lump, PU_STATIC);
ml = (mapseg_t*)data;
li = segs;
for (i = 0; i < numsegs; i++, li++, ml++)
{
li->v1 = &vertexes[SHORT(ml->v1)];
li->v2 = &vertexes[SHORT(ml->v2)];
li->angle = (SHORT(ml->angle)) << 16;
li->offset = (SHORT(ml->offset)) << 16;
linedef = SHORT(ml->linedef);
ldef = &lines[linedef];
li->linedef = ldef;
side = SHORT(ml->side);
li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector;
if (ldef->flags & ML_TWOSIDED)
li->backsector = sides[ldef->sidenum[side ^ 1]].sector;
else
li->backsector = 0;
}
Z_Free(data);
}
//
// P_LoadSubsectors
//
void P_LoadSubsectors(int lump)
{
byte* data;
int i;
mapsubsector_t* ms;
subsector_t* ss;
numsubsectors = W_LumpLength(lump) / sizeof(mapsubsector_t);
subsectors = Z_Malloc(numsubsectors * sizeof(subsector_t), PU_LEVEL, 0);
data = W_CacheLumpNum(lump, PU_STATIC);
ms = (mapsubsector_t*)data;
doom_memset(subsectors, 0, numsubsectors * sizeof(subsector_t));
ss = subsectors;
for (i = 0; i < numsubsectors; i++, ss++, ms++)
{
ss->numlines = SHORT(ms->numsegs);
ss->firstline = SHORT(ms->firstseg);
}
Z_Free(data);
}
//
// P_LoadSectors
//
void P_LoadSectors(int lump)
{
byte* data;
int i;
mapsector_t* ms;
sector_t* ss;
numsectors = W_LumpLength(lump) / sizeof(mapsector_t);
sectors = Z_Malloc(numsectors * sizeof(sector_t), PU_LEVEL, 0);
doom_memset(sectors, 0, numsectors * sizeof(sector_t));
data = W_CacheLumpNum(lump, PU_STATIC);
ms = (mapsector_t*)data;
ss = sectors;
for (i = 0; i < numsectors; i++, ss++, ms++)
{
ss->floorheight = SHORT(ms->floorheight) << FRACBITS;
ss->ceilingheight = SHORT(ms->ceilingheight) << FRACBITS;
ss->floorpic = R_FlatNumForName(ms->floorpic);
ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
ss->lightlevel = SHORT(ms->lightlevel);
ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag);
ss->thinglist = 0;
}
Z_Free(data);
}
//
// P_LoadNodes
//
void P_LoadNodes(int lump)
{
byte* data;
int i;
int j;
int k;
mapnode_t* mn;
node_t* no;
numnodes = W_LumpLength(lump) / sizeof(mapnode_t);
nodes = Z_Malloc(numnodes * sizeof(node_t), PU_LEVEL, 0);
data = W_CacheLumpNum(lump, PU_STATIC);
mn = (mapnode_t*)data;
no = nodes;
for (i = 0; i < numnodes; i++, no++, mn++)
{
no->x = SHORT(mn->x) << FRACBITS;
no->y = SHORT(mn->y) << FRACBITS;
no->dx = SHORT(mn->dx) << FRACBITS;
no->dy = SHORT(mn->dy) << FRACBITS;
for (j = 0; j < 2; j++)
{
no->children[j] = SHORT(mn->children[j]);
for (k = 0; k < 4; k++)
no->bbox[j][k] = SHORT(mn->bbox[j][k]) << FRACBITS;
}
}
Z_Free(data);
}
//
// P_LoadThings
//
void P_LoadThings(int lump)
{
byte* data;
int i;
mapthing_t* mt;
int numthings;
doom_boolean spawn;
data = W_CacheLumpNum(lump, PU_STATIC);
numthings = W_LumpLength(lump) / sizeof(mapthing_t);
mt = (mapthing_t*)data;
for (i = 0; i < numthings; i++, mt++)
{
spawn = true;
// Do not spawn cool, new monsters if !commercial
if (gamemode != commercial)
{
switch (mt->type)
{
case 68: // Arachnotron
case 64: // Archvile
case 88: // Boss Brain
case 89: // Boss Shooter
case 69: // Hell Knight
case 67: // Mancubus
case 71: // Pain Elemental
case 65: // Former Human Commando
case 66: // Revenant
case 84: // Wolf SS
spawn = false;
break;
}
}
if (spawn == false)
break;
// Do spawn all other stuff.
mt->x = SHORT(mt->x);
mt->y = SHORT(mt->y);
mt->angle = SHORT(mt->angle);
mt->type = SHORT(mt->type);
mt->options = SHORT(mt->options);
P_SpawnMapThing(mt);
}
Z_Free(data);
}
//
// P_LoadLineDefs
// Also counts secret lines for intermissions.
//
void P_LoadLineDefs(int lump)
{
byte* data;
int i;
maplinedef_t* mld;
line_t* ld;
vertex_t* v1;
vertex_t* v2;
numlines = W_LumpLength(lump) / sizeof(maplinedef_t);
lines = Z_Malloc(numlines * sizeof(line_t), PU_LEVEL, 0);
doom_memset(lines, 0, numlines * sizeof(line_t));
data = W_CacheLumpNum(lump, PU_STATIC);
mld = (maplinedef_t*)data;
ld = lines;
for (i = 0; i < numlines; i++, mld++, ld++)
{
ld->flags = SHORT(mld->flags);
ld->special = SHORT(mld->special);
ld->tag = SHORT(mld->tag);
v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
ld->dx = v2->x - v1->x;
ld->dy = v2->y - v1->y;
if (!ld->dx)
ld->slopetype = ST_VERTICAL;
else if (!ld->dy)
ld->slopetype = ST_HORIZONTAL;
else
{
if (FixedDiv(ld->dy, ld->dx) > 0)
ld->slopetype = ST_POSITIVE;
else
ld->slopetype = ST_NEGATIVE;
}
if (v1->x < v2->x)
{
ld->bbox[BOXLEFT] = v1->x;
ld->bbox[BOXRIGHT] = v2->x;
}
else
{
ld->bbox[BOXLEFT] = v2->x;
ld->bbox[BOXRIGHT] = v1->x;
}
if (v1->y < v2->y)
{
ld->bbox[BOXBOTTOM] = v1->y;
ld->bbox[BOXTOP] = v2->y;
}
else
{
ld->bbox[BOXBOTTOM] = v2->y;
ld->bbox[BOXTOP] = v1->y;
}
ld->sidenum[0] = SHORT(mld->sidenum[0]);
ld->sidenum[1] = SHORT(mld->sidenum[1]);
if (ld->sidenum[0] != -1)
ld->frontsector = sides[ld->sidenum[0]].sector;
else
ld->frontsector = 0;
if (ld->sidenum[1] != -1)
ld->backsector = sides[ld->sidenum[1]].sector;
else
ld->backsector = 0;
}
Z_Free(data);
}
//
// P_LoadSideDefs
//
void P_LoadSideDefs(int lump)
{
byte* data;
int i;
mapsidedef_t* msd;
side_t* sd;
numsides = W_LumpLength(lump) / sizeof(mapsidedef_t);
sides = Z_Malloc(numsides * sizeof(side_t), PU_LEVEL, 0);
doom_memset(sides, 0, numsides * sizeof(side_t));
data = W_CacheLumpNum(lump, PU_STATIC);
msd = (mapsidedef_t*)data;
sd = sides;
for (i = 0; i < numsides; i++, msd++, sd++)
{
sd->textureoffset = SHORT(msd->textureoffset) << FRACBITS;
sd->rowoffset = SHORT(msd->rowoffset) << FRACBITS;
sd->toptexture = R_TextureNumForName(msd->toptexture);
sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
sd->midtexture = R_TextureNumForName(msd->midtexture);
sd->sector = &sectors[SHORT(msd->sector)];
}
Z_Free(data);
}
//
// P_LoadBlockMap
//
void P_LoadBlockMap(int lump)
{
int i;
int count;
blockmaplump = W_CacheLumpNum(lump, PU_LEVEL);
blockmap = blockmaplump + 4;
count = W_LumpLength(lump) / 2;
for (i = 0; i < count; i++)
blockmaplump[i] = SHORT(blockmaplump[i]);
bmaporgx = blockmaplump[0] << FRACBITS;
bmaporgy = blockmaplump[1] << FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
// clear out mobj chains
count = sizeof(*blocklinks) * bmapwidth * bmapheight;
blocklinks = Z_Malloc(count, PU_LEVEL, 0);
doom_memset(blocklinks, 0, count);
}
//
// P_GroupLines
// Builds sector line lists and subsector sector numbers.
// Finds block bounding boxes for sectors.
//
void P_GroupLines(void)
{
line_t** linebuffer;
int i;
int j;
int total;
line_t* li;
sector_t* sector;
subsector_t* ss;
seg_t* seg;
fixed_t bbox[4];
int block;
// look up sector number for each subsector
ss = subsectors;
for (i = 0; i < numsubsectors; i++, ss++)
{
seg = &segs[ss->firstline];
ss->sector = seg->sidedef->sector;
}
// count number of lines in each sector
li = lines;
total = 0;
for (i = 0; i < numlines; i++, li++)
{
total++;
li->frontsector->linecount++;
if (li->backsector && li->backsector != li->frontsector)
{
li->backsector->linecount++;
total++;
}
}
// build line tables for each sector
linebuffer = Z_Malloc(total * sizeof(line_t*), PU_LEVEL, 0);
sector = sectors;
for (i = 0; i < numsectors; i++, sector++)
{
M_ClearBox(bbox);
sector->lines = linebuffer;
li = lines;
for (j = 0; j < numlines; j++, li++)
{
if (li->frontsector == sector || li->backsector == sector)
{
*linebuffer++ = li;
M_AddToBox(bbox, li->v1->x, li->v1->y);
M_AddToBox(bbox, li->v2->x, li->v2->y);
}
}
if (linebuffer - sector->lines != sector->linecount)
I_Error("Error: P_GroupLines: miscounted");
// set the degenmobj_t to the middle of the bounding box
sector->soundorg.x = (bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2;
sector->soundorg.y = (bbox[BOXTOP] + bbox[BOXBOTTOM]) / 2;
// adjust bounding box to map blocks
block = (bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
block = block >= bmapheight ? bmapheight - 1 : block;
sector->blockbox[BOXTOP] = block;
block = (bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
block = block < 0 ? 0 : block;
sector->blockbox[BOXBOTTOM] = block;
block = (bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
block = block >= bmapwidth ? bmapwidth - 1 : block;
sector->blockbox[BOXRIGHT] = block;
block = (bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
block = block < 0 ? 0 : block;
sector->blockbox[BOXLEFT] = block;
}
}
//
// P_SetupLevel
//
void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
{
int i;
char lumpname[9];
int lumpnum;
totalkills = totalitems = totalsecret = wminfo.maxfrags = 0;
wminfo.partime = 180;
for (i = 0; i < MAXPLAYERS; i++)
{
players[i].killcount = players[i].secretcount
= players[i].itemcount = 0;
}
// Initial height of PointOfView
// will be set by player think.
players[consoleplayer].viewz = 1;
// Make sure all sounds are stopped before Z_FreeTags.
S_Start();
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
// UNUSED W_Profile ();
P_InitThinkers();
// if working with a devlopment map, reload it
W_Reload();
// find map name
if (gamemode == commercial)
{
if (map < 10)
{
//doom_sprintf(lumpname, "map0%i", map);
doom_strcpy(lumpname, "map0");
doom_concat(lumpname, doom_itoa(map, 10));
}
else
{
//doom_sprintf(lumpname, "map%i", map);
doom_strcpy(lumpname, "map");
doom_concat(lumpname, doom_itoa(map, 10));
}
}
else
{
lumpname[0] = 'E';
lumpname[1] = '0' + episode;
lumpname[2] = 'M';
lumpname[3] = '0' + map;
lumpname[4] = 0;
}
lumpnum = W_GetNumForName(lumpname);
leveltime = 0;
// note: most of this ordering is important
P_LoadBlockMap(lumpnum + ML_BLOCKMAP);
P_LoadVertexes(lumpnum + ML_VERTEXES);
P_LoadSectors(lumpnum + ML_SECTORS);
P_LoadSideDefs(lumpnum + ML_SIDEDEFS);
P_LoadLineDefs(lumpnum + ML_LINEDEFS);
P_LoadSubsectors(lumpnum + ML_SSECTORS);
P_LoadNodes(lumpnum + ML_NODES);
P_LoadSegs(lumpnum + ML_SEGS);
rejectmatrix = W_CacheLumpNum(lumpnum + ML_REJECT, PU_LEVEL);
P_GroupLines();
bodyqueslot = 0;
deathmatch_p = deathmatchstarts;
P_LoadThings(lumpnum + ML_THINGS);
// if deathmatch, randomly spawn the active players
if (deathmatch)
{
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
players[i].mo = 0;
G_DeathMatchSpawnPlayer(i);
}
}
// clear special respawning que
iquehead = iquetail = 0;
// set up world state
P_SpawnSpecials();
// preload graphics
if (precache)
R_PrecacheLevel();
}
//
// P_Init
//
void P_Init(void)
{
P_InitSwitchList();
P_InitPicAnims();
R_InitSprites(sprnames);
}

39
src/DOOM/p_setup.h Normal file
View File

@ -0,0 +1,39 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// Setup a game, startup stuff.
//
//-----------------------------------------------------------------------------
#ifndef __P_SETUP__
#define __P_SETUP__
// NOT called by W_Ticker. Fixme.
void P_SetupLevel(int episode, int map, int playermask, skill_t skill);
// Called by startup code.
void P_Init(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

341
src/DOOM/p_sight.c Normal file
View File

@ -0,0 +1,341 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// LineOfSight/Visibility checks, uses REJECT Lookup Table.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "i_system.h"
#include "p_local.h"
#include "r_state.h" // State.
//
// P_CheckSight
//
fixed_t sightzstart; // eye z of looker
fixed_t topslope;
fixed_t bottomslope; // slopes to top and bottom of target
divline_t strace; // from t1 to t2
fixed_t t2x;
fixed_t t2y;
int sightcounts[2];
//
// P_DivlineSide
// Returns side 0 (front), 1 (back), or 2 (on).
//
int P_DivlineSide(fixed_t x, fixed_t y, divline_t* node)
{
fixed_t dx;
fixed_t dy;
fixed_t left;
fixed_t right;
if (!node->dx)
{
if (x == node->x)
return 2;
if (x <= node->x)
return node->dy > 0;
return node->dy < 0;
}
if (!node->dy)
{
if (x == node->y)
return 2;
if (y <= node->y)
return node->dx < 0;
return node->dx > 0;
}
dx = (x - node->x);
dy = (y - node->y);
left = (node->dy >> FRACBITS) * (dx >> FRACBITS);
right = (dy >> FRACBITS) * (node->dx >> FRACBITS);
if (right < left)
return 0; // front side
if (left == right)
return 2;
return 1; // back side
}
//
// P_InterceptVector2
// Returns the fractional intercept point
// along the first divline.
// This is only called by the addthings and addlines traversers.
//
fixed_t P_InterceptVector2(divline_t* v2, divline_t* v1)
{
fixed_t frac;
fixed_t num;
fixed_t den;
den = FixedMul(v1->dy >> 8, v2->dx) - FixedMul(v1->dx >> 8, v2->dy);
if (den == 0)
return 0;
num = FixedMul((v1->x - v2->x) >> 8, v1->dy) +
FixedMul((v2->y - v1->y) >> 8, v1->dx);
frac = FixedDiv(num, den);
return frac;
}
//
// P_CrossSubsector
// Returns true
// if strace crosses the given subsector successfully.
//
doom_boolean P_CrossSubsector(int num)
{
seg_t* seg;
line_t* line;
int s1;
int s2;
int count;
subsector_t* sub;
sector_t* front;
sector_t* back;
fixed_t opentop;
fixed_t openbottom;
divline_t divl;
vertex_t* v1;
vertex_t* v2;
fixed_t frac;
fixed_t slope;
#ifdef RANGECHECK
if (num >= numsubsectors)
{
//I_Error("Error: P_CrossSubsector: ss %i with numss = %i",
// num,
// numsubsectors);
doom_strcpy(error_buf, "Error: P_CrossSubsector: ss ");
doom_concat(error_buf, doom_itoa(num, 10));
doom_concat(error_buf, " with numss = ");
doom_concat(error_buf, doom_itoa(numsubsectors, 10));
I_Error(error_buf);
}
#endif
sub = &subsectors[num];
// check lines
count = sub->numlines;
seg = &segs[sub->firstline];
for (; count; seg++, count--)
{
line = seg->linedef;
// allready checked other side?
if (line->validcount == validcount)
continue;
line->validcount = validcount;
v1 = line->v1;
v2 = line->v2;
s1 = P_DivlineSide(v1->x, v1->y, &strace);
s2 = P_DivlineSide(v2->x, v2->y, &strace);
// line isn't crossed?
if (s1 == s2)
continue;
divl.x = v1->x;
divl.y = v1->y;
divl.dx = v2->x - v1->x;
divl.dy = v2->y - v1->y;
s1 = P_DivlineSide(strace.x, strace.y, &divl);
s2 = P_DivlineSide(t2x, t2y, &divl);
// line isn't crossed?
if (s1 == s2)
continue;
// stop because it is not two sided anyway
// might do this after updating validcount?
if (!(line->flags & ML_TWOSIDED))
return false;
// crosses a two sided line
front = seg->frontsector;
back = seg->backsector;
// no wall to block sight with?
if (front->floorheight == back->floorheight
&& front->ceilingheight == back->ceilingheight)
continue;
// possible occluder
// because of ceiling height differences
if (front->ceilingheight < back->ceilingheight)
opentop = front->ceilingheight;
else
opentop = back->ceilingheight;
// because of ceiling height differences
if (front->floorheight > back->floorheight)
openbottom = front->floorheight;
else
openbottom = back->floorheight;
// quick test for totally closed doors
if (openbottom >= opentop)
return false; // stop
frac = P_InterceptVector2(&strace, &divl);
if (front->floorheight != back->floorheight)
{
slope = FixedDiv(openbottom - sightzstart, frac);
if (slope > bottomslope)
bottomslope = slope;
}
if (front->ceilingheight != back->ceilingheight)
{
slope = FixedDiv(opentop - sightzstart, frac);
if (slope < topslope)
topslope = slope;
}
if (topslope <= bottomslope)
return false; // stop
}
// passed the subsector ok
return true;
}
//
// P_CrossBSPNode
// Returns true
// if strace crosses the given node successfully.
//
doom_boolean P_CrossBSPNode(int bspnum)
{
node_t* bsp;
int side;
if (bspnum & NF_SUBSECTOR)
{
if (bspnum == -1)
return P_CrossSubsector(0);
else
return P_CrossSubsector(bspnum & (~NF_SUBSECTOR));
}
bsp = &nodes[bspnum];
// decide which side the start point is on
side = P_DivlineSide(strace.x, strace.y, (divline_t*)bsp);
if (side == 2)
side = 0; // an "on" should cross both sides
// cross the starting side
if (!P_CrossBSPNode(bsp->children[side]))
return false;
// the partition plane is crossed here
if (side == P_DivlineSide(t2x, t2y, (divline_t*)bsp))
{
// the line doesn't touch the other side
return true;
}
// cross the ending side
return P_CrossBSPNode(bsp->children[side ^ 1]);
}
//
// P_CheckSight
// Returns true
// if a straight line between t1 and t2 is unobstructed.
// Uses REJECT.
//
doom_boolean P_CheckSight(mobj_t* t1, mobj_t* t2)
{
int s1;
int s2;
int pnum;
int bytenum;
int bitnum;
// First check for trivial rejection.
// Determine subsector entries in REJECT table.
s1 = (int)(t1->subsector->sector - sectors);
s2 = (int)(t2->subsector->sector - sectors);
pnum = s1 * numsectors + s2;
bytenum = pnum >> 3;
bitnum = 1 << (pnum & 7);
// Check in REJECT table.
if (rejectmatrix[bytenum] & bitnum)
{
sightcounts[0]++;
// can't possibly be connected
return false;
}
// An unobstructed LOS is possible.
// Now look from eyes of t1 to any part of t2.
sightcounts[1]++;
validcount++;
sightzstart = t1->z + t1->height - (t1->height >> 2);
topslope = (t2->z + t2->height) - sightzstart;
bottomslope = (t2->z) - sightzstart;
strace.x = t1->x;
strace.y = t1->y;
t2x = t2->x;
t2y = t2->y;
strace.dx = t2->x - t1->x;
strace.dy = t2->y - t1->y;
// the head node is the last node output
return P_CrossBSPNode(numnodes - 1);
}

1313
src/DOOM/p_spec.c Normal file

File diff suppressed because it is too large Load Diff

429
src/DOOM/p_spec.h Normal file
View File

@ -0,0 +1,429 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION: none
// Implements special effects:
// Texture animation, height or lighting changes
// according to adjacent sectors, respective
// utility functions, etc.
//
//-----------------------------------------------------------------------------
#ifndef __P_SPEC__
#define __P_SPEC__
#include "p_mobj.h"
#include "r_defs.h"
//
// End-level timer (-TIMER option)
//
extern doom_boolean levelTimer;
extern int levelTimeCount;
// Define values for map objects
#define MO_TELEPORTMAN 14
// at game start
void P_InitPicAnims(void);
// at map load
void P_SpawnSpecials(void);
// every tic
void P_UpdateSpecials(void);
// when needed
doom_boolean P_UseSpecialLine(mobj_t* thing, line_t* line, int side);
void P_ShootSpecialLine(mobj_t* thing, line_t* line);
void P_CrossSpecialLine(int linenum, int side, mobj_t* thing);
void P_PlayerInSpecialSector(player_t* player);
int twoSided(int sector, int line);
sector_t* getSector(int currentSector, int line, int side);
side_t* getSide(int currentSector, int line, int side);
fixed_t P_FindLowestFloorSurrounding(sector_t* sec);
fixed_t P_FindHighestFloorSurrounding(sector_t* sec);
fixed_t P_FindNextHighestFloor(sector_t* sec, int currentheight);
fixed_t P_FindLowestCeilingSurrounding(sector_t* sec);
fixed_t P_FindHighestCeilingSurrounding(sector_t* sec);
int P_FindSectorFromLineTag(line_t* line, int start);
int P_FindMinSurroundingLight(sector_t* sector, int max);
sector_t* getNextSector(line_t* line, sector_t* sec);
//
// SPECIAL
//
int EV_DoDonut(line_t* line);
//
// P_LIGHTS
//
typedef struct
{
thinker_t thinker;
sector_t* sector;
int count;
int maxlight;
int minlight;
} fireflicker_t;
typedef struct
{
thinker_t thinker;
sector_t* sector;
int count;
int maxlight;
int minlight;
int maxtime;
int mintime;
} lightflash_t;
typedef struct
{
thinker_t thinker;
sector_t* sector;
int count;
int minlight;
int maxlight;
int darktime;
int brighttime;
} strobe_t;
typedef struct
{
thinker_t thinker;
sector_t* sector;
int minlight;
int maxlight;
int direction;
} glow_t;
#define GLOWSPEED 8
#define STROBEBRIGHT 5
#define FASTDARK 15
#define SLOWDARK 35
void P_SpawnFireFlicker(sector_t* sector);
void T_LightFlash(lightflash_t* flash);
void P_SpawnLightFlash(sector_t* sector);
void T_StrobeFlash(strobe_t* flash);
void P_SpawnStrobeFlash(sector_t* sector, int fastOrSlow, int inSync);
void EV_StartLightStrobing(line_t* line);
void EV_TurnTagLightsOff(line_t* line);
void EV_LightTurnOn(line_t* line, int bright);
void T_Glow(glow_t* g);
void P_SpawnGlowingLight(sector_t* sector);
//
// P_SWITCH
//
typedef struct
{
char name1[9];
char name2[9];
short episode;
} switchlist_t;
typedef enum
{
top,
middle,
bottom
} bwhere_e;
typedef struct
{
line_t* line;
bwhere_e where;
int btexture;
int btimer;
mobj_t* soundorg;
} button_t;
// max # of wall switches in a level
#define MAXSWITCHES 50
// 4 players, 4 buttons each at once, max.
#define MAXBUTTONS 16
// 1 second, in ticks.
#define BUTTONTIME 35
extern button_t buttonlist[MAXBUTTONS];
void P_ChangeSwitchTexture(line_t* line, int useAgain);
void P_InitSwitchList(void);
//
// P_PLATS
//
typedef enum
{
up,
down,
waiting,
in_stasis
} plat_e;
typedef enum
{
perpetualRaise,
downWaitUpStay,
raiseAndChange,
raiseToNearestAndChange,
blazeDWUS
} plattype_e;
typedef struct
{
thinker_t thinker;
sector_t* sector;
fixed_t speed;
fixed_t low;
fixed_t high;
int wait;
int count;
plat_e status;
plat_e oldstatus;
doom_boolean crush;
int tag;
plattype_e type;
} plat_t;
#define PLATWAIT 3
#define PLATSPEED FRACUNIT
#define MAXPLATS 30
extern plat_t* activeplats[MAXPLATS];
void T_PlatRaise(plat_t* plat);
int EV_DoPlat(line_t* line, plattype_e type, int amount);
void P_AddActivePlat(plat_t* plat);
void P_RemoveActivePlat(plat_t* plat);
void EV_StopPlat(line_t* line);
void P_ActivateInStasis(int tag);
//
// P_DOORS
//
typedef enum
{
door_normal,
close30ThenOpen,
door_close,
door_open,
raiseIn5Mins,
blazeRaise,
blazeOpen,
blazeClose
} vldoor_e;
typedef struct
{
thinker_t thinker;
vldoor_e type;
sector_t* sector;
fixed_t topheight;
fixed_t speed;
// 1 = up, 0 = waiting at top, -1 = down
int direction;
// tics to wait at the top
int topwait;
// (keep in case a door going down is reset)
// when it reaches 0, start going down
int topcountdown;
} vldoor_t;
#define VDOORSPEED FRACUNIT*2
#define VDOORWAIT 150
void EV_VerticalDoor(line_t* line, mobj_t* thing);
int EV_DoDoor(line_t* line, vldoor_e type);
int EV_DoLockedDoor(line_t* line, vldoor_e type, mobj_t* thing);
void T_VerticalDoor(vldoor_t* door);
void P_SpawnDoorCloseIn30(sector_t* sec);
void P_SpawnDoorRaiseIn5Mins(sector_t* sec, int secnum);
//
// P_CEILNG
//
typedef enum
{
lowerToFloor,
raiseToHighest,
lowerAndCrush,
crushAndRaise,
fastCrushAndRaise,
silentCrushAndRaise
} ceiling_e;
typedef struct
{
thinker_t thinker;
ceiling_e type;
sector_t* sector;
fixed_t bottomheight;
fixed_t topheight;
fixed_t speed;
doom_boolean crush;
// 1 = up, 0 = waiting, -1 = down
int direction;
// ID
int tag;
int olddirection;
} ceiling_t;
#define CEILSPEED FRACUNIT
#define CEILWAIT 150
#define MAXCEILINGS 30
extern ceiling_t* activeceilings[MAXCEILINGS];
int EV_DoCeiling(line_t* line, ceiling_e type);
void T_MoveCeiling(ceiling_t* ceiling);
void P_AddActiveCeiling(ceiling_t* c);
void P_RemoveActiveCeiling(ceiling_t* c);
int EV_CeilingCrushStop(line_t* line);
void P_ActivateInStasisCeiling(line_t* line);
//
// P_FLOOR
//
typedef enum
{
// lower floor to highest surrounding floor
lowerFloor,
// lower floor to lowest surrounding floor
lowerFloorToLowest,
// lower floor to highest surrounding floor VERY FAST
turboLower,
// raise floor to lowest surrounding CEILING
raiseFloor,
// raise floor to next highest surrounding floor
raiseFloorToNearest,
// raise floor to shortest height texture around it
raiseToTexture,
// lower floor to lowest surrounding floor
// and change floorpic
lowerAndChange,
raiseFloor24,
raiseFloor24AndChange,
raiseFloorCrush,
// raise to next highest floor, turbo-speed
raiseFloorTurbo,
donutRaise,
raiseFloor512
} floor_e;
typedef enum
{
build8, // slowly build by 8
turbo16 // quickly build by 16
} stair_e;
typedef struct
{
thinker_t thinker;
floor_e type;
doom_boolean crush;
sector_t* sector;
int direction;
int newspecial;
short texture;
fixed_t floordestheight;
fixed_t speed;
} floormove_t;
#define FLOORSPEED FRACUNIT
typedef enum
{
ok,
crushed,
pastdest
} result_e;
result_e T_MovePlane(sector_t* sector, fixed_t speed, fixed_t dest, doom_boolean crush, int floorOrCeiling, int direction);
int EV_BuildStairs(line_t* line, stair_e type);
int EV_DoFloor(line_t* line, floor_e floortype);
void T_MoveFloor(floormove_t* floor);
//
// P_TELEPT
//
int EV_Teleport(line_t* line, int side, mobj_t* thing);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

612
src/DOOM/p_switch.c Normal file
View File

@ -0,0 +1,612 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//
// $Log:$
//
// DESCRIPTION:
// Switches, buttons. Two-state animation. Exits.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "i_system.h"
#include "doomdef.h"
#include "p_local.h"
#include "g_game.h"
#include "s_sound.h"
#include "sounds.h" // Data.
#include "doomstat.h" // State.
#include "r_state.h" // State.
//
// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
//
switchlist_t alphSwitchList[] =
{
// Doom shareware episode 1 switches
{"SW1BRCOM", "SW2BRCOM", 1},
{"SW1BRN1", "SW2BRN1", 1},
{"SW1BRN2", "SW2BRN2", 1},
{"SW1BRNGN", "SW2BRNGN", 1},
{"SW1BROWN", "SW2BROWN", 1},
{"SW1COMM", "SW2COMM", 1},
{"SW1COMP", "SW2COMP", 1},
{"SW1DIRT", "SW2DIRT", 1},
{"SW1EXIT", "SW2EXIT", 1},
{"SW1GRAY", "SW2GRAY", 1},
{"SW1GRAY1", "SW2GRAY1", 1},
{"SW1METAL", "SW2METAL", 1},
{"SW1PIPE", "SW2PIPE", 1},
{"SW1SLAD", "SW2SLAD", 1},
{"SW1STARG", "SW2STARG", 1},
{"SW1STON1", "SW2STON1", 1},
{"SW1STON2", "SW2STON2", 1},
{"SW1STONE", "SW2STONE", 1},
{"SW1STRTN", "SW2STRTN", 1},
// Doom registered episodes 2&3 switches
{"SW1BLUE", "SW2BLUE", 2},
{"SW1CMT", "SW2CMT", 2},
{"SW1GARG", "SW2GARG", 2},
{"SW1GSTON", "SW2GSTON", 2},
{"SW1HOT", "SW2HOT", 2},
{"SW1LION", "SW2LION", 2},
{"SW1SATYR", "SW2SATYR", 2},
{"SW1SKIN", "SW2SKIN", 2},
{"SW1VINE", "SW2VINE", 2},
{"SW1WOOD", "SW2WOOD", 2},
// Doom II switches
{"SW1PANEL", "SW2PANEL", 3},
{"SW1ROCK", "SW2ROCK", 3},
{"SW1MET2", "SW2MET2", 3},
{"SW1WDMET", "SW2WDMET", 3},
{"SW1BRIK", "SW2BRIK", 3},
{"SW1MOD1", "SW2MOD1", 3},
{"SW1ZIM", "SW2ZIM", 3},
{"SW1STON6", "SW2STON6", 3},
{"SW1TEK", "SW2TEK", 3},
{"SW1MARB", "SW2MARB", 3},
{"SW1SKULL", "SW2SKULL", 3},
{"\0", "\0", 0}
};
int switchlist[MAXSWITCHES * 2];
int numswitches;
button_t buttonlist[MAXBUTTONS];
//
// P_InitSwitchList
// Only called at game initialization.
//
void P_InitSwitchList(void)
{
int i;
int index;
int episode;
episode = 1;
if (gamemode == registered)
episode = 2;
else
if (gamemode == commercial)
episode = 3;
for (index = 0, i = 0; i < MAXSWITCHES; i++)
{
if (!alphSwitchList[i].episode)
{
numswitches = index / 2;
switchlist[index] = -1;
break;
}
if (alphSwitchList[i].episode <= episode)
{
switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name1);
switchlist[index++] = R_TextureNumForName(alphSwitchList[i].name2);
}
}
}
//
// Start a button counting down till it turns off.
//
void P_StartButton(line_t* line, bwhere_e w, int texture, int time)
{
int i;
// See if button is already pressed
for (i = 0; i < MAXBUTTONS; i++)
{
if (buttonlist[i].btimer
&& buttonlist[i].line == line)
{
return;
}
}
for (i = 0; i < MAXBUTTONS; i++)
{
if (!buttonlist[i].btimer)
{
buttonlist[i].line = line;
buttonlist[i].where = w;
buttonlist[i].btexture = texture;
buttonlist[i].btimer = time;
buttonlist[i].soundorg = (mobj_t*)&line->frontsector->soundorg;
return;
}
}
I_Error("Error: P_StartButton: no button slots left!");
}
//
// Function that changes wall texture.
// Tell it if switch is ok to use again (1=yes, it's a button).
//
void P_ChangeSwitchTexture(line_t* line, int useAgain)
{
int texTop;
int texMid;
int texBot;
int i;
int sound;
if (!useAgain)
line->special = 0;
texTop = sides[line->sidenum[0]].toptexture;
texMid = sides[line->sidenum[0]].midtexture;
texBot = sides[line->sidenum[0]].bottomtexture;
sound = sfx_swtchn;
// EXIT SWITCH?
if (line->special == 11)
sound = sfx_swtchx;
for (i = 0; i < numswitches * 2; i++)
{
if (switchlist[i] == texTop)
{
S_StartSound(buttonlist->soundorg, sound);
sides[line->sidenum[0]].toptexture = switchlist[i ^ 1];
if (useAgain)
P_StartButton(line, top, switchlist[i], BUTTONTIME);
return;
}
else
{
if (switchlist[i] == texMid)
{
S_StartSound(buttonlist->soundorg, sound);
sides[line->sidenum[0]].midtexture = switchlist[i ^ 1];
if (useAgain)
P_StartButton(line, middle, switchlist[i], BUTTONTIME);
return;
}
else
{
if (switchlist[i] == texBot)
{
S_StartSound(buttonlist->soundorg, sound);
sides[line->sidenum[0]].bottomtexture = switchlist[i ^ 1];
if (useAgain)
P_StartButton(line, bottom, switchlist[i], BUTTONTIME);
return;
}
}
}
}
}
//
// P_UseSpecialLine
// Called when a thing uses a special line.
// Only the front sides of lines are usable.
//
doom_boolean P_UseSpecialLine(mobj_t* thing, line_t* line, int side)
{
// Err...
// Use the back sides of VERY SPECIAL lines...
if (side)
{
switch (line->special)
{
case 124:
// Sliding door open&close
// UNUSED?
break;
default:
return false;
break;
}
}
// Switches that other things can activate.
if (!thing->player)
{
// never open secret doors
if (line->flags & ML_SECRET)
return false;
switch (line->special)
{
case 1: // MANUAL DOOR RAISE
case 32: // MANUAL BLUE
case 33: // MANUAL RED
case 34: // MANUAL YELLOW
break;
default:
return false;
break;
}
}
// do something
switch (line->special)
{
// MANUALS
case 1: // Vertical Door
case 26: // Blue Door/Locked
case 27: // Yellow Door /Locked
case 28: // Red Door /Locked
case 31: // Manual door open
case 32: // Blue locked door open
case 33: // Red locked door open
case 34: // Yellow locked door open
case 117: // Blazing door raise
case 118: // Blazing door open
EV_VerticalDoor(line, thing);
break;
//UNUSED - Door Slide Open&Close
// case 124:
// EV_SlidingDoor (line, thing);
// break;
// SWITCHES
case 7:
// Build Stairs
if (EV_BuildStairs(line, build8))
P_ChangeSwitchTexture(line, 0);
break;
case 9:
// Change Donut
if (EV_DoDonut(line))
P_ChangeSwitchTexture(line, 0);
break;
case 11:
// Exit level
P_ChangeSwitchTexture(line, 0);
G_ExitLevel();
break;
case 14:
// Raise Floor 32 and change texture
if (EV_DoPlat(line, raiseAndChange, 32))
P_ChangeSwitchTexture(line, 0);
break;
case 15:
// Raise Floor 24 and change texture
if (EV_DoPlat(line, raiseAndChange, 24))
P_ChangeSwitchTexture(line, 0);
break;
case 18:
// Raise Floor to next highest floor
if (EV_DoFloor(line, raiseFloorToNearest))
P_ChangeSwitchTexture(line, 0);
break;
case 20:
// Raise Plat next highest floor and change texture
if (EV_DoPlat(line, raiseToNearestAndChange, 0))
P_ChangeSwitchTexture(line, 0);
break;
case 21:
// PlatDownWaitUpStay
if (EV_DoPlat(line, downWaitUpStay, 0))
P_ChangeSwitchTexture(line, 0);
break;
case 23:
// Lower Floor to Lowest
if (EV_DoFloor(line, lowerFloorToLowest))
P_ChangeSwitchTexture(line, 0);
break;
case 29:
// Raise Door
if (EV_DoDoor(line, door_normal))
P_ChangeSwitchTexture(line, 0);
break;
case 41:
// Lower Ceiling to Floor
if (EV_DoCeiling(line, lowerToFloor))
P_ChangeSwitchTexture(line, 0);
break;
case 71:
// Turbo Lower Floor
if (EV_DoFloor(line, turboLower))
P_ChangeSwitchTexture(line, 0);
break;
case 49:
// Ceiling Crush And Raise
if (EV_DoCeiling(line, crushAndRaise))
P_ChangeSwitchTexture(line, 0);
break;
case 50:
// Close Door
if (EV_DoDoor(line, door_close))
P_ChangeSwitchTexture(line, 0);
break;
case 51:
// Secret EXIT
P_ChangeSwitchTexture(line, 0);
G_SecretExitLevel();
break;
case 55:
// Raise Floor Crush
if (EV_DoFloor(line, raiseFloorCrush))
P_ChangeSwitchTexture(line, 0);
break;
case 101:
// Raise Floor
if (EV_DoFloor(line, raiseFloor))
P_ChangeSwitchTexture(line, 0);
break;
case 102:
// Lower Floor to Surrounding floor height
if (EV_DoFloor(line, lowerFloor))
P_ChangeSwitchTexture(line, 0);
break;
case 103:
// Open Door
if (EV_DoDoor(line, door_open))
P_ChangeSwitchTexture(line, 0);
break;
case 111:
// Blazing Door Raise (faster than TURBO!)
if (EV_DoDoor(line, blazeRaise))
P_ChangeSwitchTexture(line, 0);
break;
case 112:
// Blazing Door Open (faster than TURBO!)
if (EV_DoDoor(line, blazeOpen))
P_ChangeSwitchTexture(line, 0);
break;
case 113:
// Blazing Door Close (faster than TURBO!)
if (EV_DoDoor(line, blazeClose))
P_ChangeSwitchTexture(line, 0);
break;
case 122:
// Blazing PlatDownWaitUpStay
if (EV_DoPlat(line, blazeDWUS, 0))
P_ChangeSwitchTexture(line, 0);
break;
case 127:
// Build Stairs Turbo 16
if (EV_BuildStairs(line, turbo16))
P_ChangeSwitchTexture(line, 0);
break;
case 131:
// Raise Floor Turbo
if (EV_DoFloor(line, raiseFloorTurbo))
P_ChangeSwitchTexture(line, 0);
break;
case 133:
// BlzOpenDoor BLUE
case 135:
// BlzOpenDoor RED
case 137:
// BlzOpenDoor YELLOW
if (EV_DoLockedDoor(line, blazeOpen, thing))
P_ChangeSwitchTexture(line, 0);
break;
case 140:
// Raise Floor 512
if (EV_DoFloor(line, raiseFloor512))
P_ChangeSwitchTexture(line, 0);
break;
// BUTTONS
case 42:
// Close Door
if (EV_DoDoor(line, door_close))
P_ChangeSwitchTexture(line, 1);
break;
case 43:
// Lower Ceiling to Floor
if (EV_DoCeiling(line, lowerToFloor))
P_ChangeSwitchTexture(line, 1);
break;
case 45:
// Lower Floor to Surrounding floor height
if (EV_DoFloor(line, lowerFloor))
P_ChangeSwitchTexture(line, 1);
break;
case 60:
// Lower Floor to Lowest
if (EV_DoFloor(line, lowerFloorToLowest))
P_ChangeSwitchTexture(line, 1);
break;
case 61:
// Open Door
if (EV_DoDoor(line, door_open))
P_ChangeSwitchTexture(line, 1);
break;
case 62:
// PlatDownWaitUpStay
if (EV_DoPlat(line, downWaitUpStay, 1))
P_ChangeSwitchTexture(line, 1);
break;
case 63:
// Raise Door
if (EV_DoDoor(line, door_normal))
P_ChangeSwitchTexture(line, 1);
break;
case 64:
// Raise Floor to ceiling
if (EV_DoFloor(line, raiseFloor))
P_ChangeSwitchTexture(line, 1);
break;
case 66:
// Raise Floor 24 and change texture
if (EV_DoPlat(line, raiseAndChange, 24))
P_ChangeSwitchTexture(line, 1);
break;
case 67:
// Raise Floor 32 and change texture
if (EV_DoPlat(line, raiseAndChange, 32))
P_ChangeSwitchTexture(line, 1);
break;
case 65:
// Raise Floor Crush
if (EV_DoFloor(line, raiseFloorCrush))
P_ChangeSwitchTexture(line, 1);
break;
case 68:
// Raise Plat to next highest floor and change texture
if (EV_DoPlat(line, raiseToNearestAndChange, 0))
P_ChangeSwitchTexture(line, 1);
break;
case 69:
// Raise Floor to next highest floor
if (EV_DoFloor(line, raiseFloorToNearest))
P_ChangeSwitchTexture(line, 1);
break;
case 70:
// Turbo Lower Floor
if (EV_DoFloor(line, turboLower))
P_ChangeSwitchTexture(line, 1);
break;
case 114:
// Blazing Door Raise (faster than TURBO!)
if (EV_DoDoor(line, blazeRaise))
P_ChangeSwitchTexture(line, 1);
break;
case 115:
// Blazing Door Open (faster than TURBO!)
if (EV_DoDoor(line, blazeOpen))
P_ChangeSwitchTexture(line, 1);
break;
case 116:
// Blazing Door Close (faster than TURBO!)
if (EV_DoDoor(line, blazeClose))
P_ChangeSwitchTexture(line, 1);
break;
case 123:
// Blazing PlatDownWaitUpStay
if (EV_DoPlat(line, blazeDWUS, 0))
P_ChangeSwitchTexture(line, 1);
break;
case 132:
// Raise Floor Turbo
if (EV_DoFloor(line, raiseFloorTurbo))
P_ChangeSwitchTexture(line, 1);
break;
case 99:
// BlzOpenDoor BLUE
case 134:
// BlzOpenDoor RED
case 136:
// BlzOpenDoor YELLOW
if (EV_DoLockedDoor(line, blazeOpen, thing))
P_ChangeSwitchTexture(line, 1);
break;
case 138:
// Light Turn On
EV_LightTurnOn(line, 255);
P_ChangeSwitchTexture(line, 1);
break;
case 139:
// Light Turn Off
EV_LightTurnOn(line, 35);
P_ChangeSwitchTexture(line, 1);
break;
}
return true;
}

117
src/DOOM/p_telept.c Normal file
View File

@ -0,0 +1,117 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Teleportation.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "s_sound.h"
#include "p_local.h"
#include "sounds.h" // Data.
#include "r_state.h" // State.
//
// TELEPORTATION
//
int EV_Teleport(line_t* line, int side, mobj_t* thing)
{
int i;
int tag;
mobj_t* m;
mobj_t* fog;
unsigned an;
thinker_t* thinker;
sector_t* sector;
fixed_t oldx;
fixed_t oldy;
fixed_t oldz;
// don't teleport missiles
if (thing->flags & MF_MISSILE)
return 0;
// Don't teleport if hit back of line,
// so you can get out of teleporter.
if (side == 1)
return 0;
tag = line->tag;
for (i = 0; i < numsectors; i++)
{
if (sectors[i].tag == tag)
{
thinker = thinkercap.next;
for (thinker = thinkercap.next;
thinker != &thinkercap;
thinker = thinker->next)
{
// not a mobj
if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
m = (mobj_t*)thinker;
// not a teleportman
if (m->type != MT_TELEPORTMAN)
continue;
sector = m->subsector->sector;
// wrong sector
if (sector - sectors != i)
continue;
oldx = thing->x;
oldy = thing->y;
oldz = thing->z;
if (!P_TeleportMove(thing, m->x, m->y))
return 0;
thing->z = thing->floorz; //fixme: not needed?
if (thing->player)
thing->player->viewz = thing->z + thing->player->viewheight;
// spawn teleport fog at source and destination
fog = P_SpawnMobj(oldx, oldy, oldz, MT_TFOG);
S_StartSound(fog, sfx_telept);
an = m->angle >> ANGLETOFINESHIFT;
fog = P_SpawnMobj(m->x + 20 * finecosine[an], m->y + 20 * finesine[an]
, thing->z, MT_TFOG);
// emit sound, where?
S_StartSound(fog, sfx_telept);
// don't move for a bit
if (thing->player)
thing->reactiontime = 18;
thing->angle = m->angle;
thing->momx = thing->momy = thing->momz = 0;
return 1;
}
}
}
return 0;
}

138
src/DOOM/p_tick.c Normal file
View File

@ -0,0 +1,138 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Archiving: SaveGame I/O.
// Thinker, Ticker.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "z_zone.h"
#include "p_local.h"
#include "doomstat.h"
int leveltime;
//
// THINKERS
// All thinkers should be allocated by Z_Malloc
// so they can be operated on uniformly.
// The actual structures will vary in size,
// but the first element must be thinker_t.
//
// Both the head and tail of the thinker list.
thinker_t thinkercap;
//
// P_InitThinkers
//
void P_InitThinkers(void)
{
thinkercap.prev = thinkercap.next = &thinkercap;
}
//
// P_AddThinker
// Adds a new thinker at the end of the list.
//
void P_AddThinker(thinker_t* thinker)
{
thinkercap.prev->next = thinker;
thinker->next = &thinkercap;
thinker->prev = thinkercap.prev;
thinkercap.prev = thinker;
}
//
// P_RemoveThinker
// Deallocation is lazy -- it will not actually be freed
// until its thinking turn comes up.
//
void P_RemoveThinker(thinker_t* thinker)
{
// FIXME: NOP.
thinker->function.acv = (actionf_v)(-1);
}
//
// P_RunThinkers
//
void P_RunThinkers(void)
{
thinker_t* currentthinker;
currentthinker = thinkercap.next;
while (currentthinker != &thinkercap)
{
if (currentthinker->function.acv == (actionf_v)(-1))
{
// time to remove it
currentthinker->next->prev = currentthinker->prev;
currentthinker->prev->next = currentthinker->next;
Z_Free(currentthinker);
}
else
{
if (currentthinker->function.acp1)
currentthinker->function.acp1(currentthinker);
}
currentthinker = currentthinker->next;
}
}
//
// P_Ticker
//
void P_Ticker(void)
{
int i;
// run the tic
if (paused)
return;
// pause if in menu and at least one tic has been run
if (!netgame
&& menuactive
&& !demoplayback
&& players[consoleplayer].viewz != 1)
{
return;
}
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
P_PlayerThink(&players[i]);
P_RunThinkers();
P_UpdateSpecials();
P_RespawnSpecials();
// for par times
leveltime++;
}

38
src/DOOM/p_tick.h Normal file
View File

@ -0,0 +1,38 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// ?
//
//-----------------------------------------------------------------------------
#ifndef __P_TICK__
#define __P_TICK__
// Called by C_Ticker,
// can call G_PlayerExited.
// Carries out all thinking of monsters and players.
void P_Ticker(void);
#endif
//-----------------------------------------------------------------------------
//
// $Log:$
//
//-----------------------------------------------------------------------------

370
src/DOOM/p_user.c Normal file
View File

@ -0,0 +1,370 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Player related stuff.
// Bobbing POV/weapon, movement.
// Pending weapon.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "d_event.h"
#include "p_local.h"
#include "doomstat.h"
// Index of the special effects (INVUL inverse) map.
#define INVERSECOLORMAP 32
// 16 pixels of bob
#define MAXBOB 0x100000
#define ANG5 (ANG90/18)
//
// Movement.
//
doom_boolean onground;
//
// P_Thrust
// Moves the given origin along a given angle.
//
void P_Thrust(player_t* player, angle_t angle, fixed_t move)
{
angle >>= ANGLETOFINESHIFT;
player->mo->momx += FixedMul(move, finecosine[angle]);
player->mo->momy += FixedMul(move, finesine[angle]);
}
//
// P_CalcHeight
// Calculate the walking / running height adjustment
//
void P_CalcHeight(player_t* player)
{
int angle;
fixed_t bob;
// Regular movement bobbing
// (needs to be calculated for gun swing
// even if not on ground)
// OPTIMIZE: tablify angle
// Note: a LUT allows for effects
// like a ramp with low health.
player->bob =
FixedMul(player->mo->momx, player->mo->momx)
+ FixedMul(player->mo->momy, player->mo->momy);
player->bob >>= 2;
if (player->bob > MAXBOB)
player->bob = MAXBOB;
if ((player->cheats & CF_NOMOMENTUM) || !onground)
{
player->viewz = player->mo->z + VIEWHEIGHT;
if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT)
player->viewz = player->mo->ceilingz - 4 * FRACUNIT;
player->viewz = player->mo->z + player->viewheight;
return;
}
angle = (FINEANGLES / 20 * leveltime) & FINEMASK;
bob = FixedMul(player->bob / 2, finesine[angle]);
// move viewheight
if (player->playerstate == PST_LIVE)
{
player->viewheight += player->deltaviewheight;
if (player->viewheight > VIEWHEIGHT)
{
player->viewheight = VIEWHEIGHT;
player->deltaviewheight = 0;
}
if (player->viewheight < VIEWHEIGHT / 2)
{
player->viewheight = VIEWHEIGHT / 2;
if (player->deltaviewheight <= 0)
player->deltaviewheight = 1;
}
if (player->deltaviewheight)
{
player->deltaviewheight += FRACUNIT / 4;
if (!player->deltaviewheight)
player->deltaviewheight = 1;
}
}
player->viewz = player->mo->z + player->viewheight + bob;
if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT)
player->viewz = player->mo->ceilingz - 4 * FRACUNIT;
}
//
// P_MovePlayer
//
void P_MovePlayer(player_t* player)
{
ticcmd_t* cmd;
cmd = &player->cmd;
player->mo->angle += (cmd->angleturn << 16);
// Do not let the player control movement
// if not onground.
onground = (player->mo->z <= player->mo->floorz);
if (cmd->forwardmove && onground)
P_Thrust(player, player->mo->angle, cmd->forwardmove * 2048);
if (cmd->sidemove && onground)
P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2048);
if ((cmd->forwardmove || cmd->sidemove)
&& player->mo->state == &states[S_PLAY])
{
P_SetMobjState(player->mo, S_PLAY_RUN1);
}
}
//
// P_DeathThink
// Fall on your face when dying.
// Decrease POV height to floor height.
//
void P_DeathThink(player_t* player)
{
angle_t angle;
angle_t delta;
P_MovePsprites(player);
// fall to the ground
if (player->viewheight > 6 * FRACUNIT)
player->viewheight -= FRACUNIT;
if (player->viewheight < 6 * FRACUNIT)
player->viewheight = 6 * FRACUNIT;
player->deltaviewheight = 0;
onground = (player->mo->z <= player->mo->floorz);
P_CalcHeight(player);
if (player->attacker && player->attacker != player->mo)
{
angle = R_PointToAngle2(player->mo->x,
player->mo->y,
player->attacker->x,
player->attacker->y);
delta = angle - player->mo->angle;
if (delta < ANG5 || delta >(unsigned) - ANG5)
{
// Looking at killer,
// so fade damage flash down.
player->mo->angle = angle;
if (player->damagecount)
player->damagecount--;
}
else if (delta < ANG180)
player->mo->angle += ANG5;
else
player->mo->angle -= ANG5;
}
else if (player->damagecount)
player->damagecount--;
if (player->cmd.buttons & BT_USE)
player->playerstate = PST_REBORN;
}
//
// P_PlayerThink
//
void P_PlayerThink(player_t* player)
{
ticcmd_t* cmd;
weapontype_t newweapon;
// fixme: do this in the cheat code
if (player->cheats & CF_NOCLIP)
player->mo->flags |= MF_NOCLIP;
else
player->mo->flags &= ~MF_NOCLIP;
// chain saw run forward
cmd = &player->cmd;
if (player->mo->flags & MF_JUSTATTACKED)
{
cmd->angleturn = 0;
cmd->forwardmove = 0xc800 / 512;
cmd->sidemove = 0;
player->mo->flags &= ~MF_JUSTATTACKED;
}
if (player->playerstate == PST_DEAD)
{
P_DeathThink(player);
return;
}
// Move around.
// Reactiontime is used to prevent movement
// for a bit after a teleport.
if (player->mo->reactiontime)
player->mo->reactiontime--;
else
P_MovePlayer(player);
P_CalcHeight(player);
if (player->mo->subsector->sector->special)
P_PlayerInSpecialSector(player);
// Check for weapon change.
// A special event has no other buttons.
if (cmd->buttons & BT_SPECIAL)
cmd->buttons = 0;
if (cmd->buttons & BT_CHANGE)
{
// The actual changing of the weapon is done
// when the weapon psprite can do it
// (read: not in the middle of an attack).
newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT;
if (newweapon == wp_fist
&& player->weaponowned[wp_chainsaw]
&& !(player->readyweapon == wp_chainsaw
&& player->powers[pw_strength]))
{
newweapon = wp_chainsaw;
}
if ((gamemode == commercial)
&& newweapon == wp_shotgun
&& player->weaponowned[wp_supershotgun]
&& player->readyweapon != wp_supershotgun)
{
newweapon = wp_supershotgun;
}
if (player->weaponowned[newweapon]
&& newweapon != player->readyweapon)
{
// Do not go to plasma or BFG in shareware,
// even if cheated.
if ((newweapon != wp_plasma
&& newweapon != wp_bfg)
|| (gamemode != shareware))
{
player->pendingweapon = newweapon;
}
}
}
// check for use
if (cmd->buttons & BT_USE)
{
if (!player->usedown)
{
P_UseLines(player);
player->usedown = true;
}
}
else
player->usedown = false;
// cycle psprites
P_MovePsprites(player);
// Counters, time dependend power ups.
// Strength counts up to diminish fade.
if (player->powers[pw_strength])
player->powers[pw_strength]++;
if (player->powers[pw_invulnerability])
player->powers[pw_invulnerability]--;
if (player->powers[pw_invisibility])
if (!--player->powers[pw_invisibility])
player->mo->flags &= ~MF_SHADOW;
if (player->powers[pw_infrared])
player->powers[pw_infrared]--;
if (player->powers[pw_ironfeet])
player->powers[pw_ironfeet]--;
if (player->damagecount)
player->damagecount--;
if (player->bonuscount)
player->bonuscount--;
// Handling colormaps.
if (player->powers[pw_invulnerability])
{
if (player->powers[pw_invulnerability] > 4 * 32
|| (player->powers[pw_invulnerability] & 8))
player->fixedcolormap = INVERSECOLORMAP;
else
player->fixedcolormap = 0;
}
else if (player->powers[pw_infrared])
{
if (player->powers[pw_infrared] > 4 * 32
|| (player->powers[pw_infrared] & 8))
{
// almost full bright
player->fixedcolormap = 1;
}
else
player->fixedcolormap = 0;
}
else
player->fixedcolormap = 0;
}

563
src/DOOM/r_bsp.c Normal file
View File

@ -0,0 +1,563 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// BSP traversal, handling of LineSegs for rendering.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "m_bbox.h"
#include "i_system.h"
#include "r_main.h"
#include "r_plane.h"
#include "r_things.h"
#include "doomstat.h" // State.
#include "r_state.h" // State.
#define MAXSEGS 32
//
// ClipWallSegment
// Clips the given range of columns
// and includes it in the new clip list.
//
typedef struct
{
int first;
int last;
} cliprange_t;
seg_t* curline;
side_t* sidedef;
line_t* linedef;
sector_t* frontsector;
sector_t* backsector;
drawseg_t drawsegs[MAXDRAWSEGS];
drawseg_t* ds_p;
// newend is one past the last valid seg
cliprange_t* newend;
cliprange_t solidsegs[MAXSEGS];
int checkcoord[12][4] =
{
{3,0,2,1},
{3,0,2,0},
{3,1,2,0},
{0},
{2,0,2,1},
{0,0,0,0},
{3,1,3,0},
{0},
{2,0,3,1},
{2,1,3,1},
{2,1,3,0}
};
void R_StoreWallRange(int start, int stop);
//
// R_ClearDrawSegs
//
void R_ClearDrawSegs(void)
{
ds_p = drawsegs;
}
//
// R_ClipSolidWallSegment
// Does handle solid walls,
// e.g. single sided LineDefs (middle texture)
// that entirely block the view.
//
void R_ClipSolidWallSegment(int first, int last)
{
cliprange_t* next;
cliprange_t* start;
// Find the first range that touches the range
// (adjacent pixels are touching).
start = solidsegs;
while (start->last < first - 1)
start++;
if (first < start->first)
{
if (last < start->first - 1)
{
// Post is entirely visible (above start),
// so insert a new clippost.
R_StoreWallRange(first, last);
next = newend;
newend++;
while (next != start)
{
*next = *(next - 1);
next--;
}
next->first = first;
next->last = last;
return;
}
// There is a fragment above *start.
R_StoreWallRange(first, start->first - 1);
// Now adjust the clip size.
start->first = first;
}
// Bottom contained in start?
if (last <= start->last)
return;
next = start;
while (last >= (next + 1)->first - 1)
{
// There is a fragment between two posts.
R_StoreWallRange(next->last + 1, (next + 1)->first - 1);
next++;
if (last <= next->last)
{
// Bottom is contained in next.
// Adjust the clip size.
start->last = next->last;
goto crunch;
}
}
// There is a fragment after *next.
R_StoreWallRange(next->last + 1, last);
// Adjust the clip size.
start->last = last;
// Remove start+1 to next from the clip list,
// because start now covers their area.
crunch:
if (next == start)
{
// Post just extended past the bottom of one post.
return;
}
while (next++ != newend)
{
// Remove a post.
*++start = *next;
}
newend = start + 1;
}
//
// R_ClipPassWallSegment
// Clips the given range of columns,
// but does not includes it in the clip list.
// Does handle windows,
// e.g. LineDefs with upper and lower texture.
//
void R_ClipPassWallSegment(int first, int last)
{
cliprange_t* start;
// Find the first range that touches the range
// (adjacent pixels are touching).
start = solidsegs;
while (start->last < first - 1)
start++;
if (first < start->first)
{
if (last < start->first - 1)
{
// Post is entirely visible (above start).
R_StoreWallRange(first, last);
return;
}
// There is a fragment above *start.
R_StoreWallRange(first, start->first - 1);
}
// Bottom contained in start?
if (last <= start->last)
return;
while (last >= (start + 1)->first - 1)
{
// There is a fragment between two posts.
R_StoreWallRange(start->last + 1, (start + 1)->first - 1);
start++;
if (last <= start->last)
return;
}
// There is a fragment after *next.
R_StoreWallRange(start->last + 1, last);
}
//
// R_ClearClipSegs
//
void R_ClearClipSegs(void)
{
solidsegs[0].first = -0x7fffffff;
solidsegs[0].last = -1;
solidsegs[1].first = viewwidth;
solidsegs[1].last = 0x7fffffff;
newend = solidsegs + 2;
}
//
// R_AddLine
// Clips the given segment
// and adds any visible pieces to the line list.
//
void R_AddLine(seg_t* line)
{
int x1;
int x2;
angle_t angle1;
angle_t angle2;
angle_t span;
angle_t tspan;
curline = line;
// OPTIMIZE: quickly reject orthogonal back sides.
angle1 = R_PointToAngle(line->v1->x, line->v1->y);
angle2 = R_PointToAngle(line->v2->x, line->v2->y);
// Clip to view edges.
// OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW).
span = angle1 - angle2;
// Back side? I.e. backface culling?
if (span >= ANG180)
return;
// Global angle needed by segcalc.
rw_angle1 = angle1;
angle1 -= viewangle;
angle2 -= viewangle;
tspan = angle1 + clipangle;
if (tspan > 2 * clipangle)
{
tspan -= 2 * clipangle;
// Totally off the left edge?
if (tspan >= span)
return;
angle1 = clipangle;
}
tspan = clipangle - angle2;
if (tspan > 2 * clipangle)
{
tspan -= 2 * clipangle;
// Totally off the left edge?
if (tspan >= span)
return;
#pragma warning(push)
#pragma warning(disable : 4146)
angle2 = -clipangle;
#pragma warning(pop)
}
// The seg is in the view range,
// but not necessarily visible.
angle1 = (angle1 + ANG90) >> ANGLETOFINESHIFT;
angle2 = (angle2 + ANG90) >> ANGLETOFINESHIFT;
x1 = viewangletox[angle1];
x2 = viewangletox[angle2];
// Does not cross a pixel?
if (x1 == x2)
return;
backsector = line->backsector;
// Single sided line?
if (!backsector)
goto clipsolid;
// Closed door.
if (backsector->ceilingheight <= frontsector->floorheight
|| backsector->floorheight >= frontsector->ceilingheight)
goto clipsolid;
// Window.
if (backsector->ceilingheight != frontsector->ceilingheight
|| backsector->floorheight != frontsector->floorheight)
goto clippass;
// Reject empty lines used for triggers
// and special events.
// Identical floor and ceiling on both sides,
// identical light levels on both sides,
// and no middle texture.
if (backsector->ceilingpic == frontsector->ceilingpic
&& backsector->floorpic == frontsector->floorpic
&& backsector->lightlevel == frontsector->lightlevel
&& curline->sidedef->midtexture == 0)
{
return;
}
clippass:
R_ClipPassWallSegment(x1, x2 - 1);
return;
clipsolid:
R_ClipSolidWallSegment(x1, x2 - 1);
}
//
// R_CheckBBox
// Checks BSP node/subtree bounding box.
// Returns true
// if some part of the bbox might be visible.
//
doom_boolean R_CheckBBox(fixed_t* bspcoord)
{
int boxx;
int boxy;
int boxpos;
fixed_t x1;
fixed_t y1;
fixed_t x2;
fixed_t y2;
angle_t angle1;
angle_t angle2;
angle_t span;
angle_t tspan;
cliprange_t* start;
int sx1;
int sx2;
// Find the corners of the box
// that define the edges from current viewpoint.
if (viewx <= bspcoord[BOXLEFT])
boxx = 0;
else if (viewx < bspcoord[BOXRIGHT])
boxx = 1;
else
boxx = 2;
if (viewy >= bspcoord[BOXTOP])
boxy = 0;
else if (viewy > bspcoord[BOXBOTTOM])
boxy = 1;
else
boxy = 2;
boxpos = (boxy << 2) + boxx;
if (boxpos == 5)
return true;
x1 = bspcoord[checkcoord[boxpos][0]];
y1 = bspcoord[checkcoord[boxpos][1]];
x2 = bspcoord[checkcoord[boxpos][2]];
y2 = bspcoord[checkcoord[boxpos][3]];
// check clip list for an open space
angle1 = R_PointToAngle(x1, y1) - viewangle;
angle2 = R_PointToAngle(x2, y2) - viewangle;
span = angle1 - angle2;
// Sitting on a line?
if (span >= ANG180)
return true;
tspan = angle1 + clipangle;
if (tspan > 2 * clipangle)
{
tspan -= 2 * clipangle;
// Totally off the left edge?
if (tspan >= span)
return false;
angle1 = clipangle;
}
tspan = clipangle - angle2;
if (tspan > 2 * clipangle)
{
tspan -= 2 * clipangle;
// Totally off the left edge?
if (tspan >= span)
return false;
#pragma warning(push)
#pragma warning(disable : 4146)
angle2 = -clipangle;
#pragma warning(pop)
}
// Find the first clippost
// that touches the source post
// (adjacent pixels are touching).
angle1 = (angle1 + ANG90) >> ANGLETOFINESHIFT;
angle2 = (angle2 + ANG90) >> ANGLETOFINESHIFT;
sx1 = viewangletox[angle1];
sx2 = viewangletox[angle2];
// Does not cross a pixel.
if (sx1 == sx2)
return false;
sx2--;
start = solidsegs;
while (start->last < sx2)
start++;
if (sx1 >= start->first
&& sx2 <= start->last)
{
// The clippost contains the new span.
return false;
}
return true;
}
//
// R_Subsector
// Determine floor/ceiling planes.
// Add sprites of things in sector.
// Draw one or more line segments.
//
void R_Subsector(int num)
{
int count;
seg_t* line;
subsector_t* sub;
#ifdef RANGECHECK
if (num >= numsubsectors)
{
//I_Error("Error: R_Subsector: ss %i with numss = %i",
// num,
// numsubsectors);
doom_strcpy(error_buf, "Error: R_Subsector: ss ");
doom_concat(error_buf, doom_itoa(num, 10));
doom_concat(error_buf, " with numss = ");
doom_concat(error_buf, doom_itoa(numsubsectors, 10));
I_Error(error_buf);
}
#endif
sscount++;
sub = &subsectors[num];
frontsector = sub->sector;
count = sub->numlines;
line = &segs[sub->firstline];
if (frontsector->floorheight < viewz)
{
floorplane = R_FindPlane(frontsector->floorheight,
frontsector->floorpic,
frontsector->lightlevel);
}
else
floorplane = 0;
if (frontsector->ceilingheight > viewz
|| frontsector->ceilingpic == skyflatnum)
{
ceilingplane = R_FindPlane(frontsector->ceilingheight,
frontsector->ceilingpic,
frontsector->lightlevel);
}
else
ceilingplane = 0;
R_AddSprites(frontsector);
while (count--)
{
R_AddLine(line);
line++;
}
}
//
// RenderBSPNode
// Renders all subsectors below a given node,
// traversing subtree recursively.
// Just call with BSP root.
void R_RenderBSPNode(int bspnum)
{
node_t* bsp;
int side;
// Found a subsector?
if (bspnum & NF_SUBSECTOR)
{
if (bspnum == -1)
R_Subsector(0);
else
R_Subsector(bspnum & (~NF_SUBSECTOR));
return;
}
bsp = &nodes[bspnum];
// Decide which side the view point is on.
side = R_PointOnSide(viewx, viewy, bsp);
// Recursively divide front space.
R_RenderBSPNode(bsp->children[side]);
// Possibly divide back space.
if (R_CheckBBox(bsp->bbox[side ^ 1]))
R_RenderBSPNode(bsp->children[side ^ 1]);
}

Some files were not shown because too many files have changed in this diff Show More